2013-02-05 89 views
0

編寫一個方法removeEvenLength,它將一組字符串作爲參數,並從集合中刪除所有長度均勻的字符串。這段代碼爲什麼會拋出ConcurrentModificationException?

我的解決辦法:

public static void removeEvenLength(Set<String> set) { 
    for(String word : set) { 
     if(word.length() % 2 == 0) { 
      set.remove(word); 
     } 
    } 
} 

輸入: [foo, buzz, bar, fork, bort, spoon, !, dude]

輸出:

ConcurrentModificationException on line 2: 
java.util.ConcurrentModificationException 
    at java.util.TreeMap$PrivateEntryIterator.nextEntry(TreeMap.java:1115) 
    at java.util.TreeMap$KeyIterator.next(TreeMap.java:1169) 
    at removeEvenLength (Line 2) 

這樣我就可以通過創建一個Iterator解決這個問題。但我想知道爲什麼上面的代碼不起作用?

編輯:

迭代器無法正常工作或:

public static void removeEvenLength(Set<String> set) { 
    Iterator<String> i = set.iterator(); 
    while(i.hasNext()) { 
     String word = i.next(); 
     if(word.length() % 2 == 0) { 
      set.remove(word); 
     } 
    } 
} 

同樣的錯誤。

+0

「爲什麼」:集合java.util中不是線程安全的。正因爲如此,他們添加了一個檢查來測試在迭代器中詢問下一個項目時集合是否發生了變化。如果是這樣,它會拋出ConcurrentModification異常。使用Iterator.remove是安全的,因爲它是執行步行和刪除的同一個對象。 –

+0

您的方法簽名可能應該更改爲'public static void removeEvenLength(Collection strings)',因爲這樣可以使用_any_類的集合('Iterable strings'也是一個選項)。 –

回答

5

在此迭代中iterator對象被隱式創建。當您有iterator時,您可以僅從迭代器更改集合。在這種情況下,您直接刪除對象,這就是引發此異常的原因。

創建迭代器,並與迭代器刪除對象:

iterator.remove(); // removes current element 
+0

'iterator'也不起作用!請參閱OP中的編輯。 – user2027425

+0

你正在直接刪除對象,看到mu答案更好。 – partlov

+0

'iterator.remove()'不帶任何參數,因爲它隱式地移除了'返回的最後一個元素'。但是,是的,這是問題所在。 –

2

要理解爲什麼ConcurrentModificationException發生時,你將不得不瞭解fail-fast迭代的概念。如果一個線程遍歷一個集合,並且它意識到集合在迭代過程中被修改,迭代器將拋出一個異常,而不是「可能」在代碼中引發任何完整性問題。

當然,並非所有的迭代器都遵循這種方法,並且使用Java Iterator將幾乎總能確保迭代永遠不會在修改時失敗。

要使用迭代器刪除元素,使用此代碼

Iterator<String> iter = list.iterator(); 
    while(iter.hasNext()) { 
     String obj = iter.next(); 
     if(<removal_condition_here>) { 
      iter.remove(); 
     } 
    } 
相關問題