java-關於List刪除元素的出錯問題
阿新 • • 發佈:2020-12-28
java-關於List刪除元素的出錯問題
問題
最近發現直接使用list.remove(item)時報了以下錯誤:
java.util.ConcurrentModificationException: null
解決方法如下:
Iterator<OrderDetl> iterator = list.iterator(); while(iterator.hasNext()){ OrderDetl detl = iterator.next(); for (int i = 0; i < bookIds.size(); i++) { if (detl.getBookId().equals(bookIds.get(i))) { iterator.remove(); //剔除 break; } } } // 以下刪除方法會報錯 // for (OrderDetl detl : list) { // for (int i = 0; i < bookIds.size(); i++) { // if (detl.getBookId().equals(bookIds.get(i))) { // list.remove(detl); //剔除 // break; // } // } // }
原因:
呼叫list.remove()方法導致modCount和expectedModCount的值不一致。
原始碼分析
ArrayList中的remove()方法:
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; } private void fastRemove(int index) { modCount++; int numMoved = size - index - 1; if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--size] = null; // Let gc do its work }
通過remove方法刪除元素最終是呼叫的fastRemove()方法,在fastRemove()方法中,首先對modCount進行加1操作(因為對集合修改了一次),然後接下來就是刪除元素的操作,最後將size進行減1操作,並將引用置為null以方便垃圾收集器進行回收工作。
那麼注意此時各個變數的值:對於iterator,其expectedModCount為0,cursor的值為1,lastRet的值為0。
對於list,其modCount為1,size為0。
接著看程式程式碼,執行完刪除操作後,繼續while迴圈,呼叫hasNext方法()判斷,由於此時cursor為1,而size為0,那麼返回true,所以繼續執行while迴圈,然後繼續呼叫iterator的next()方法:
注意,此時要注意next()方法中的第一句:checkForComodification()。
在checkForComodification方法中進行的操作是:
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
如果modCount不等於expectedModCount,則丟擲ConcurrentModificationException異常。
很顯然,此時modCount為1,而expectedModCount為0,因此程式就丟擲了ConcurrentModificationException異常。