如Java中的容器Map:
for(Person person : pList){
if(person.getGender()==Gender.MALE){
pList.remove(person); //不能在遍歷期間進行remove這個操作
}
}
Map在遍歷時候通常現獲得其鍵值的集合Set,然後用迭代器Iterator來對Map進行遍歷。
注意在遍歷的過程中,只能對Map中的元素進行對應的處理,不能把Map元素增加或把Map元素減少,也就是說,不能改變Map的size大小,就會出現異常(不能在遍歷過程中修改刪除或增加map中的元素)
報出的異常為java.util.ConcurrentModificationException 異常
public class ConcurrentModificationExceptionextends RuntimeException
當方法偵測到物件的並發修改,但不允許這種修改時,請拋出此異常。
例如,某個執行緒在Collection 上進行迭代時,通常不允許另一個線性修改該Collection。通常在這些情況下,迭代的結果是不明確的。如果偵測到這種行為,一些迭代器實作(包括JRE 提供的所有通用collection 實作)可能會選擇拋出此異常。執行該操作的迭代器稱為快速失敗迭代器,因為迭代器很快就完全失敗,而不會冒著在將來某個時間任意發生不確定行為的風險。
注意,此異常不會始終指出物件已經由不同執行緒並發修改。如果單執行緒發出違反物件協定的方法呼叫序列,則該物件可能會拋出此異常。例如,如果執行緒使用快速失敗迭代器在collection 上迭代時直接修改該collection,則迭代器將拋出此異常。
請注意,迭代器的快速失敗行為無法得到保證,因為一般來說,不可能對是否出現不同步並發修改做出任何硬性保證。快速失敗操作會盡力拋出ConcurrentModificationException。因此,為提高此類操作的正確性而編寫一個依賴此異常的程式是錯誤的做法,正確做法是:ConcurrentModificationException 應該僅用於檢測bug。
當使用fail-fast iterator 對Collection 或Map 進行迭代操作過程中嘗試直接修改Collection / Map 的內容時,即使是在單執行緒下運行, java.util.ConcurrentModificationException 例外也會被拋出。
Iterator 是工作在一個獨立的執行緒中,並且擁有一個mutex 鎖。 Iterator 被創建之後會建立一個指向原來物件的單鏈索引表,當原來的物件數量發生變化時,這個索引表的內容不會同步改變,所以當索引指標往後移動的時候就找不到要迭代的對象,所以按照fail-fast 原則Iterator 會馬上拋出java.util.ConcurrentModificationException 異常。
所以Iterator 在工作的時候是不允許被迭代的物件被改變的。但你可以使用Iterator 本身的方法remove() 來刪除對象, Iterator.remove() 方法會在刪除目前迭代對象的同時維護索引的一致性。
有趣的是如果你的Collection / Map 物件實際上只有一個元素的時候, ConcurrentModificationException 異常並不會被拋出。這也就是為什麼在javadoc 裡面指出: it would be wrong to write a program that depended on this exception for its correctness: ConcurrentModificationException should be used only to detect bugs.