1. 程式人生 > >list的數據遍歷時的刪除錯誤及其解決辦法

list的數據遍歷時的刪除錯誤及其解決辦法

變化 獨立 ORC -c AI 工作 刪除對象 exc expected

在遍歷list而且特定條件下需要刪除剛剛遍歷完的一個元素時調用的remove(object)會報如下錯誤:技術分享圖片主要是因為Iterator 是工作在一個獨立的線程中,並且擁有一個 mutex 鎖。 Iterator 被創建之後會建立一個指向原來對象的單鏈索引表,當原來的對象數量發生變化時,這個索引表的內容不會同步改變,所以當索引指針往後移動的時候就找不到要叠代的對象,所以按照 fail-fast 原則 Iterator 會馬上拋出 java.util.ConcurrentModificationException 異常。Iterator 在工作的時候是不允許被叠代的對象被改變的。但你可以使用 Iterator 本身的方法 remove() 來刪除對象, Iterator.remove() 方法會在刪除當前叠代對象的同時維護索引的一致性。是在於foreach方式遍歷元素的時候,是生成iterator,然後使用iterator遍歷。在生成iterator的時候,會保存一個expectedModCount參數,這個是生成iterator的時候List中修改元素的次數。如果你在遍歷過程中刪除元素,List中modCount就會變化,如果這個modCount和exceptedModCount不一致,就會拋出異常,這個是為了安全的考慮。

foreach的remove(Object)的源碼:

  • public boolean remove(Object o) {
  • if (o == null) {
  • for (int index = 0; index < size; index++)
  • if (elementData[index] == null) {
  • fastRemove(index);
  • return true;
  • }
  • } else {
  • for (int index = 0; index < size; index++)
  • if (o.equals(elementData[index])) {
  • fastRemove(index);
  • return true;
  • }
  • }
  • return false;
  • } 沒有對expectedModCount進行任何修改,導致expectedModCount和modCount不一致,拋出異常。 iterear的remove()源碼
    • public void remove() {
    • if (lastRet < 0)
    • throw new IllegalStateException();
    • checkForComodification();
    • try {
    • ArrayList.this.remove(lastRet);
    • cursor = lastRet;
    • lastRet = -1;
    • expectedModCount = modCount;//處理expectedModCount
    • } catch (IndexOutOfBoundsException ex) {
    • throw new ConcurrentModificationException();
    • }
    • } 對expectedModCount重新做了賦值處理的。這樣的話保持expectedModCount = modCount相等,就不會報出錯了。

list的數據遍歷時的刪除錯誤及其解決辦法