1. 程式人生 > 實用技巧 >java-關於List刪除元素的出錯問題

java-關於List刪除元素的出錯問題

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異常。