java遍歷list刪除元素講解,java遍歷list刪除元素

在路上壓死只雞,剛想找人商量賠償。

看見一小女孩!我:「孩子!這是你家的雞么?」

孩子:「不是!我家的雞沒有這麼扁。」‍

ArrayList使用forEach遍歷的時候刪除元素會報錯嗎?

答:其實不一定,如果刪除的元素是倒數第二個則不會報錯,否則報錯ConcurrentModificationException。(答,會報錯,也沒毛病)

原因:舉個例子

List<String> lists = new ArrayList<String>();

lists.add("1");

lists.add("2");

lists.add("3");

lists.add("4");

如果要刪除等於「3」的元素,我們都知道ArrayList底層是類似數組的形式才存儲數據的,生成一個元素後,後面的元素要往前移動,同時lists的size減1。這時lists變成[「1」,「2」,「4」],大小為3。

使用forEach遍歷時:

for(String s :lists){
 if(s.equals("3")){
  lists.remove(s);
 }
}
                     
//這是一顆語法糖,編譯後相當於:
for(Iterator i = lists.iterator();i.hasNext();){
    String s = (String)i.next();
    if(s.equals("3")){
        list.remove(s);
    }
}                  

Iterator的hasNext()方法判斷了size和當前下標cursor是否一樣,一樣則說明已經沒有元素了。

如果remove了「3」這個元素之後,size會變成3,這時候遍歷的下標cursor剛好是3,因此不會再進行下一次循環,直接結束了,此時元素「4」是沒有被遍歷到的。

假如lists中的元素是[「1」,「2」,「3」,「4」,「5」],即3不再是倒數第二個元素了呢?

此時會進行下一次循環,先判斷i.hasNext(),發現當前下標cursor不等於size,執行i.next(),試圖取出下一個值「4」,這時候就報錯了,原因在i.next()中:

public E next() {
    checkForComodification();
    int i = cursor;
    if (i >= size)
        throw new NoSuchElementException();
    Object[] elementData = ArrayList.this.elementData;
    if (i >= elementData.length)
        throw new ConcurrentModificationException();
    cursor = i + 1;
    return (E) elementData[lastRet = i];
}
final void checkForComodification() {
    if (modCount != expectedModCount)
       throw new ConcurrentModificationException();
}

Iterator取下一個值時候會先判斷modCount是否和expectedModCount一樣,不一樣就報錯。

這裡的modCount是刪除的元素的數量計數,expectedModCount是Iterator期望的刪除數量,使用Iterator的remove()方法的時候,Iterator會將調用ArrayList.this.remove(lastRet)刪除元素同時使得modCount++,然後將modCount的值賦給expectedModCount,確保它們一樣。

所以到這裡我們就可以發現問題了,在forEach循環體里,我們直接使用的是lists.remove(「3」)的方法來刪除元素,導致了expectedModCount和modCount不一致。

所以要在遍歷的時候刪除元素,不能使用forEach遍歷的方式,要使用Iterator的方法。

下面是修改後的代碼:

String s= null;
for(Iterator i = lists.iterator(); i.hasNext(); ){
   s=(String)i.next();
   if(s.equals("3")){
       i.remove();
   }
}

還有一種方法是使用CopyOnWriteArrayList代替ArrayList,這是一種寫時複製的容器,每次添加刪除元素的時候都會複製一份舊的數據,新建一個新數據,在新數據進行修改後再修改舊數據的指針指到新數據。

這樣的話,遍歷的數據其實都是第一份的舊數據,舊數據是沒有變的,我們使用舊數據遍歷,使用新數據判斷值。

畫個圖表達下我的理解:

ArrayList使用forEach遍歷的時候刪除元素會報錯嗎?

來源:blog.csdn.net/awocbb/article/details/85069427

原創文章,作者:投稿專員,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/229803.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
投稿專員的頭像投稿專員
上一篇 2024-12-10 13:16
下一篇 2024-12-10 13:16

相關推薦

發表回復

登錄後才能評論