現在有一個需求,要遍歷一個List,假設List里面存儲的是String對象,然后該需求事判斷里面如果有某個對象,則添加一個新的對象進去。自然,我們得出下面的代碼:
import java.util.ArrayList; import java.util.Iterator; import java.util.List;/*** Created by lili on 15/11/13.*/ public class Test {public static void main(String[] args) {List list = new ArrayList();list.add("lucy");list.add("polo");list.add("shery");//Exception in thread "main" java.util.ConcurrentModificationExceptionIterator it = list.iterator();while (it.hasNext()){String str = (String)it.next();if(str.equals("polo")){list.add("pony");}}} }
但是該段代碼會報錯:ConcurrentModificationException,在API中查詢這個異常,解釋如下:
public class ConcurrentModificationException extends RuntimeException 當方法檢測到對象的并發修改,但不允許這種修改時,拋出此異常。例如,某個線程在 Collection 上進行迭代時,通常不允許另一個線性修改該 Collection。通常在這些情況下,迭代的結果是不確定的。如果檢測到這種行為,一些迭代器實現(包括 JRE 提供的所有通用 collection 實現)可能選擇拋出此異常。執行該操作的迭代器稱為快速失敗 迭代器,因為迭代器很快就完全失敗,而不會冒著在將來某個時間任意發生不確定行為的風險。注意,此異常不會始終指出對象已經由不同 線程并發修改。如果單線程發出違反對象協定的方法調用序列,則該對象可能拋出此異常。例如,如果線程使用快速失敗迭代器在 collection 上迭代時直接修改該 collection,則迭代器將拋出此異常。注意,迭代器的快速失敗行為無法得到保證,因為一般來說,不可能對是否出現不同步并發修改做出任何硬性保證。快速失敗操作會盡最大努力拋出 ConcurrentModificationException。因此,為提高此類操作的正確性而編寫一個依賴于此異常的程序是錯誤的做法,正確做法是:ConcurrentModificationException 應該僅用于檢測 bug。從以下版本開始: 1.2
從這個異常的說明來看,這種異常還不單單對List,是對所有的Collection容器(List,Set),如果在迭代的時候有修改,則都會出現。
那怎樣才能解決這個問題呢?
- 用迭代器自身去添加對象,但是要利用ListIterator進行添加:Iterator只有hashNext,next和remove方法,而ListIterator有add和向前遍歷的方法。
- 改用for循環來遍歷判斷并添加。
import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.ListIterator;/*** Created by lili on 15/11/13.*/ public class Test {public static void main(String[] args) {List list = new ArrayList();list.add("lucy");list.add("polo");list.add("shery");//Exception in thread "main" java.util.ConcurrentModificationException // Iterator it = list.iterator(); // while (it.hasNext()){ // String str = (String)it.next(); // if(str.equals("polo")){ // list.add("pony"); // } // } ListIterator listIt = list.listIterator();while (listIt.hasNext()){String str = (String) listIt.next();if(str.equals("polo")){listIt.add("pony");}if(str.equals("shery")){listIt.add("keity");}}System.out.println(list);for(int i = 0; i < list.size(); i++){if(list.get(i).equals("polo")){list.add("pony");}if(list.get(i).equals("shery")){list.add("keity");}}System.out.println(list);} }
但是從打印的結果來看,這兩種添加還是有區別的,第一種方式是在當前遍歷元素后面添加,第二種是在最后面追加。
[lucy, polo, pony, shery, keity]
[lucy, polo, pony, shery, keity, pony, keity]Process finished with exit code 0
?