1. 程式人生 > >Java中集合迴圈刪除元素的問題

Java中集合迴圈刪除元素的問題

1、在一個迴圈中刪除一個列表中的元素

思考下面這一段在迴圈中刪除多個元素的的程式碼

Java程式碼
  1. ArrayList<String> list = new ArrayList<String>(Arrays.asList("a","b","c","d"));  
  2. for(int i=0;i<list.size();i++){  
  3.     list.remove(i);  
  4. }  
  5. System.out.println(list);  

輸出結果是:

Java程式碼
  1. [b,d]  

在這個方法中有一個嚴重的錯誤。當一個元素被刪除時,列表的大小縮小並且下標變化,所以當你想要在一個迴圈中用下標刪除多個元素的時候,它並不會正常的生效。

你也許知道在迴圈中正確的刪除多個元素的方法是使用迭代,並且你知道java中的foreach迴圈看起來像一個迭代器,但實際上並不是。考慮一下下面的程式碼:

Java程式碼
  1. ArrayList<String> list = 
    new ArrayList<String>(Arrays.asList("a","b","c","d"));  
  2. for(String s:list){  
  3.     if(s.equals("a")){  
  4.         list.remove(s);  
  5.     }  
  6. }  

它會丟擲一個ConcurrentModificationException異常。

相反下面的顯示正常:

Java程式碼
  1. ArrayList<String> list = new ArrayList<String>(Arrays.asList("a","b","c","d"));  
  2. Iterator<String> iter = list.iterator();  
  3. while(iter.hasNext()){  
  4.         String s = iter.next();  
  5.         if(s.equals("a")){  
  6.             iter.remove();  
  7.     }  
  8. }  
基本上ArrayList採用size屬性來維護自已的狀態,而Iterator採用cursor來來維護自已的狀態。

當size出現變化時,cursor並不一定能夠得到同步,除非這種變化是Iterator主動導致的。

從上面的程式碼可以看到當Iterator.remove方法導致ArrayList列表發生變化時,他會更新cursor來同步這一變化。但其他方式導致

ArrayList變化,Iterator是無法感知的。ArrayList自然也不會主動通知Iterator們,那將是一個繁重的工作。Iterator到底還是做了努力:為了防止狀態不一致可能引發的無法設想的後果,Iterator會經常做checkForComodification檢查,以防有變。如果有變,則以異常丟擲,所以就出現了上面的異常。