[英]ConcurrentModificationException while iterating through HashMap
[英]How I can get ConcurrentModificationException while iterating Hashmap?
我試圖將一個鍵值對添加到Iterator方法內的哈希圖中。
但這並沒有給我ConcurrentModificationException
。 為什么?
由於Hashmap是fastfast。
Map<String,String> m = new HashMap<>();
m.put("a", "a");
Iterator<String> i = m.keySet().iterator();
while(i.hasNext()){
System.out.println(i.next());
m.put("dsad", "asfsdf");
}
如果這是錯誤的,我如何產生ConcurrentModificationException? 謝謝。
更新:剛剛檢查。
Map<String,String> m = new HashMap<>();
m.put("a", "a");
m.put("abc", "a");
Iterator<String> i = m.keySet().iterator();
while(i.hasNext()){
System.out.println(i.next());
m.put("dsad", "asfsdf");
}
這給了我一個例外。
碰巧,由HashMap
代碼完成的並發修改檢查無法檢測到這種情況。 Oracle JDK7中HashMap
的迭代器hasNext
的代碼是:
public final boolean hasNext() {
return next != null;
}
...在哪里(令人困惑!) next
是迭代器類中的私有數據成員(不要與Iterator
接口上的next
方法相混淆-在我看來,將數據成員稱為next
是一個非常糟糕的選擇)。
請注意,它不會檢查並發修改。 與此代碼(從Iterator#next
間接調用)對比:
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
......這確實做檢查。
因此,這就是您的代碼中發生的情況:
HashMap
。 hasNext
是真的,因此您進入了循環的主體。 next
元素; 在這一點上,迭代器會記住下一個元素應該在其內部數據成員上的名稱(這個名稱易混淆的next
),在這種情況下,由於映射中沒有下一個元素,因此next
數據成員被設置為null
,這意味着迭代完成。 hasNext
,它看到next
數據成員為null
並返回false
。 如果在開始循環之前在映射中有兩個元素而不是一個,則將獲得異常(來自next
)。
我以前曾說過,這是一個bug,或者幾乎是一個bug,但這是一個非常模糊的領域,而其他人則相當合理地認為不是。 該文檔沒有具體說明Iterator<E>
哪些方法將引發異常,而只是引發該異常。 該文檔還說,這只是出於“盡力而為”的原則,不能保證。
無論是否認為它是一個錯誤,在這一點上都不太可能更改,因為更改它的痛苦(破壞一些本不應該依賴此行為的現有代碼)遠遠超過了好處(可能更“正確”) “)。
迭代器可能會拋出ConcurrentModificationException,但不能保證如此。
從HashMap的javadoc中:
請注意,迭代器的快速失敗行為無法得到保證,因為通常來說,在存在不同步的並發修改的情況下,不可能做出任何嚴格的保證。 快速失敗的迭代器會盡最大努力拋出ConcurrentModificationException。 因此,編寫依賴於此異常的程序以確保其正確性是錯誤的:迭代器的快速失敗行為應僅用於檢測錯誤。
嘗試這個:
Map<String,String> m = new HashMap<>();
m.put("a", "a");
Iterator<String> i = m.keySet().iterator();
while(i.hasNext()){
m.remove("a");
System.out.println(i.next());
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.