在遍歷List時,對List裏的對象進行remove(),此操作會改變List的大小()

先看看代碼:

1 for(ComType com : ComList){
2    if(!com.getName.contains("abc")){
3       CosList.remove(com);
4    }
5 }

通過這段代碼,並沒有過濾掉不包含“abc”的元素。經過測試分析得到結論是:在每一次remove()時,改變了CosList的大小(size),導致CosList遍歷不完整。

空指針空指針
發帖於 1年前
14回/5391閱

按票數排序  顯示最新答案  共有14個答案 (最後回答: 1年前)

    1
  • liuex
    簡化的for-each循環實際上只是一個語法糖,會被編譯器轉化成以下等價的代碼:
    1 for( Iterator<ComType> iter = ComList.iterator(); iter.hasNext();){
    2     ComType com = iter.next();
    3     if ( !com.getName().contains("abc")){
    4         ComList.remove(com);
    5     }
    6 }

    也就是說,你在同時遍歷和刪除一個List,大多List實現是不允許這種操作的(某些List實現允許同時遍歷和修改,例如CopyOnWriteArrayList),會拋併發修改異常。(具體可以參考ArrayList的源代碼,ArrayList上面的ArrayList.iterator()操作會記錄當前的修改次數modCount,remove/add操作會讓修改次數自增,即modCount++,因此就能判斷出來是否是併發修改了)

    解決方法:

    使用Iterator遍歷的同時,使用Iterator.remove()刪除你想刪除的元素。另外也可以參考一下ListIterator,上面有很多針對List的方法。

    1 for( Iterator<ComType> iter = ComList.iterator(); iter.hasNext();){
    2     ComType com = iter.next();
    3     if ( !com.getName().contains("abc")){
    4         iter.remove(com);
    5     }
    6 }

    --- 共有 1 條評論 ---
    • 西部倒貼iter.remove(com); 這個地方錯了吧? 應該是 iter.remove();吧 (1年前)   
    0
  • 棉花

    倒,不能這麼遍歷。

    for(int i = ComList.size() -1 ; i >= 0; i--){

    if(!ComList.get(i).getName.contains("abc")){

        CosList.remove(com);
    }

    }

    0
  • 棉花

    修正下

     

    for(int i = ComList.size() -1 ; i >= 0; i--){

    if(!ComList.get(i).getName.contains("abc")){

    CosList.remove(i);
    }

    }

    0
  • 紅薯
    如果要在遍歷過程中刪除元素,應該用迭代器,同 @liuex 的方法 
    --- 共有 1 條評論 ---
    • 要做攻城師的志不用迭代器,在刪除元素之後,馬上break掉,也是可以的,這樣更簡單 (1年前)   
    0
  • 三毛々
    LZ在remove的時候居然沒有給你拋出異常。真是奇怪。
    --- 共有 2 條評論 ---
    • 王國表回覆 @java_cmm : 我這樣弄就報錯了,他們竟然會不報錯? (1年前)   
    • helloming同感。。。 (1年前)   
    0
  • Monkey
    我又一個問題,樓主那樣的代碼不會出異常? for-each是不能添加刪除的,不然就出異常, Iterator這個爛東西只能遍歷,而且一旦容器發生變化這玩意就作廢,繼續訪問就異常。
    --- 共有 1 條評論 ---
    0
  • 引用來自“liuex”的答案

    簡化的for-each循環實際上只是一個語法糖,會被編譯器轉化成以下等價的代碼:
    1 for( Iterator<ComType> iter = ComList.iterator(); iter.hasNext();){
    2     ComType com = iter.next();
    3     if ( !com.getName().contains("abc")){
    4         ComList.remove(com);
    5     }
    6 }

    也就是說,你在同時遍歷和刪除一個List,大多List實現是不允許這種操作的(某些List實現允許同時遍歷和修改,例如CopyOnWriteArrayList),會拋併發修改異常。(具體可以參考ArrayList的源代碼,ArrayList上面的ArrayList.iterator()操作會記錄當前的修改次數modCount,remove/add操作會讓修改次數自增,即modCount++,因此就能判斷出來是否是併發修改了)

    解決方法:

    使用Iterator遍歷的同時,使用Iterator.remove()刪除你想刪除的元素。另外也可以參考一下ListIterator,上面有很多針對List的方法。

    1 for( Iterator<ComType> iter = ComList.iterator(); iter.hasNext();){
    2     ComType com = iter.next();
    3     if ( !com.getName().contains("abc")){
    4         iter.remove(com);
    5     }
    6 }

    +1
    0
  • 愛coding

    1.集合在迭代期間,不能調用集合的add(),remove(),set()等方法,這就好像數雞蛋,不允許在數雞蛋的時候,突然把雞蛋拿走了,

    2.如果需要迭代的時候刪除集合元素,可以調用迭代器的刪除方法,ite.remove()刪除當前元素,而不是集合的remove方法。

    0
  • buptwhis

    一般地,還是用函數式的編程方式來解決這種問題比較好

    比如要過濾掉這上list的一些元素時,不是直接在這個list上面remove掉某個元素。而是在遍歷這個list,把不需要過濾的元素收集起來加到一個新的list裏面,完全避免這種問題

    --- 共有 2 條評論 ---
    0
  • java9
    用iterator來操作集合.你這種方法會改變集合的大小.
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章