不要在 foreach 循環里進行元素的 remove/add 操作。remove 元素請使用 Iterator 方式。
反例:
public class ForeachTest { private List<String> list = new ArrayList<String>(); @Test public void forTest() { list.add("1"); list.add("2"); for(String temp : list) { if("1".equals(temp)) { list.remove(temp); } } for(String temp : list) { System.out.println(temp + " "); } } }
結果
如果將1換成2,結果就出錯了
產生Concurrent Modification Exception原因是:當list.remove(Object o)方法之后,modCount和expectedModCount不相等了,然后當代碼執行到next()方法時,判斷了checkForComodification(),發現兩個數值不等,就拋出該Exception;add(Object o)方法也是一樣原因;
另外,Iterator是工作在一個獨立的線程中,並且擁有一個mutex鎖, Iterator 被創建之后會建立一個指向原來對象的單鏈索引表,當原來的list對象數量發生變化時,這個索引表的內容不會同步改變,所以當索引指針往后移動的時候就找不到要迭代的對象,所以按照 fail-fast 原則 Iterator 會馬上拋出 java.util.ConcurrentModificationException 異常。 所以 Iterator 在工作的時候是不允許被迭代的對象被改變的。
但你可以使用 Iterator 本身的方法 remove() 來刪除對象, Iterator.remove() 方法會在刪除當前迭代對象的同時維護索引的一致性。
正例:
public class ForeachTest { private List<String> list = new ArrayList<String>(); @Test public void forTest2() { list.add("1"); list.add("2"); Iterator<String> it = list.iterator(); while(it.hasNext()) { String temp = it.next(); if("2".equals(temp)) { it.remove(); } } for(String temp : list) { System.out.println(temp + " "); } } }
結果很完美,
如果並發操作,需要對 Iterator 對象加鎖。