2013-01-08 51 views
1

這是一個跟進我剛纔的問題:只有一條線爪哇 - Collection.remove()具有不同的行爲在不同條件下

Collection - Iterator.remove() vs Collection.remove()

下面的代碼,這顯然是不同的兩片,但有一個拋出異常,其他拋出異常。你能解釋一下這個區別嗎?

List<String> list = new ArrayList<String> 
(Arrays.asList("noob1","noob2","noob3")); 


System.out.println(list); 

for (String str : list) { 
    if (str.equals("noob2")) { 
     list.remove(str); 
    } 
} 

運行正常,但如果我改變的條件

if (!str.equals("noob2")) 

代碼拋出異常!

+4

什麼異常? –

+1

java.util.ConcurrentModificationException – NINCOMPOOP

+0

但它如何取決於「if」條件? – NINCOMPOOP

回答

4

在這種情況下會發生什麼,您將刪除第二個列表元素。

List<String> list = new ArrayList<String> 
     (Arrays.asList("noob1", "noob2", "noob3", "noob4")); 

System.out.println(list); 

for (Iterator<String> iterator = list.iterator(); iterator.hasNext();) { 
    String str = iterator.next(); 
    if (str.equals("noob3")) { 
     System.out.println("Checking "+str); 
     list.remove(str); 
    } 
} 
System.out.println(list); 

打印

[noob1, noob2, noob3, noob4] 
Checking noob1 
Checking noob2 
Checking noob3 
[noob1, noob2, noob4] 

通過去除將大小已經減少到您已遍歷元件的數量的第二最後一個元素。

// from ArrayList.Itr 
    public boolean hasNext() { 
     return cursor != size; 
    } 

這導致環前next()進行併發modifcation檢查提前退出。如果你刪除任何其他元素next()被調用,你會得到一個CME。

BTW一些​​東西,也繞過檢查

for (Iterator<String> iterator = list.iterator(); iterator.hasNext();) { 
    String str = iterator.next(); 
    System.out.println("Checking "+str); 
    if (str.equals("noob2")) { 
     list.remove("noob1"); 
     list.remove("noob3"); 
    } 
} 

只要集合的大小是一樣的,因爲它是到指數,不進行檢查。

1

for循環只是列表的迭代器掃描的簡化語法。如果列表在其下被修改,迭代器可能會引發異常,但不能保證。由於hasNext,迭代器通常會提前處理一個元素,使得第一種情況不太可能受到列表修改的影響。到「noob2」被刪除的時候,迭代器已經知道「noob3」了。

1

我想這個例外是因爲你試圖改變你正在循環的集合而不是因爲if條件。

我建議您創建一個新的列表只包含驗證條件的項目。將它們添加到新列表中,並避免更改原始集合。

1

實際上,在「隨意」迭代過程中,您絕對不應該刪除集合的元素。如果必須在某個循環中修改集合,則必須使用iterator來執行這些操作。

public class Test { 
     public static void main(String... args) { 
      List<String> list = new ArrayList<String>(Arrays.asList("noob1", "noob2", "noob3")); 

      System.out.println(list); 

      for (Iterator<String> iterator = list.iterator(); iterator.hasNext();) { 
       String str = iterator.next(); 
       if (!str.equals("noob2")) { 
        iterator.remove(); 
       } 
      } 
      System.out.println(list); 
     } 
    } 
1

這是因爲您試圖從Collection中刪除您目前正在迭代。做一個小小的改變,你可以做你想做的事:

String[] strValues = {"noob1","noob2","noob3"}; // <<< Array 
List<String> list = new ArrayList<String>(Arrays.asList(strValues)); 

System.out.println(list); 

for (String str : strValues) { // << List is duplicate of array so can iterate through array 
    if (!str.equals("noob2")) { 
     list.remove(str); 
    } 
} 

這應該工作。希望

0

嗯,你的第一個情況,因爲迭代器的索引2,你在索引中移除元素Iterator.hasNext()返回false不會拋出異常1.

Iterator<String> itr = list.iterator(); 
    while(itr.hasNext()){ 
     String s= itr.next(); 
     if(s.equals("noob2")){ 
      list.remove(s); // size of the list is 2 here 
      System.out.println(itr.hasNext());// this returns false as it doesn't have anything at index 2 now.(on 2nd iteration) 
     } 
    } 

你可以測試它清楚地使用一個簡單的for循環:

for (int i=0; i<list.size(); i++) { 
     if (list.get(i).equals("noob2")) { 
      System.out.println(list.get(i)); 
      System.out.println(list.size()); 
      list.remove(list.get(i)); 
      System.out.println(list.size()); 
     } 
    } 

輸出:

[noob1, noob2, noob3] 
noob2 
3 
2 

通知噸他刪除元素後列表的大小,增加後失敗。 這是假的