簡體   English   中英

如何在迭代Hashmap時獲取ConcurrentModificationException?

[英]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();

......這確實做檢查。

因此,這就是您的代碼中發生的情況:

  1. 您創建一個HashMap
  2. 您添加一個條目。
  3. 您開始迭代。
  4. hasNext是真的,因此您進入了循環的主體。
  5. next元素; 在這一點上,迭代器會記住下一個元素應該在其內部數據成員上的名稱(這個名稱易混淆的next ),在這種情況下,由於映射中沒有下一個元素,因此next數據成員被設置為null ,這意味着迭代完成。
  6. 您添加到地圖。
  7. 您的代碼調用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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM