Java 如何在迭代Hashmap时获得ConcurrentModificationException?

Java 如何在迭代Hashmap时获得ConcurrentModificationException?,java,collections,iterator,hashmap,Java,Collections,Iterator,Hashmap,我试图在迭代器方法中向hashmap添加一个键值对 但这并没有给我带来ConcurrentModificationException。为什么? 因为Hashmap是快速失效的 Map<String,String> m = new HashMap<>(); m.put("a", "a"); Iterator<String> i = m.keySet().iterator(); while(i.h

我试图在迭代器方法中向hashmap添加一个键值对

但这并没有给我带来
ConcurrentModificationException
。为什么?

因为Hashmap是快速失效的

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");

           }
Map m=newhashmap();
m、 将(“a”、“a”);
迭代器i=m.keySet().Iterator();
while(i.hasNext()){
System.out.println(i.next());
m、 看跌期权(“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");

               }
Map m=newhashmap();
m、 将(“a”、“a”);
m、 卖出(“abc”、“a”);
迭代器i=m.keySet().Iterator();
while(i.hasNext()){
System.out.println(i.next());
m、 看跌期权(“dsad”、“asfsdf”);
}

这给了我一个例外。

恰巧,
HashMap
代码执行的并发修改检查无法检测到这种情况。Oracle JDK7中的
HashMap
迭代器的
hasNext
的代码是:

public final boolean hasNext() {
    return next != null;
}
…其中(令人困惑!)表示
next
是迭代器类中的私有数据成员(不要与
iterator
接口上的
next
方法混淆-在我看来,调用该数据成员
next
是一个非常糟糕的选择)

注意,它不会检查并发修改。与从
迭代器#next
中(间接)调用的此代码相比:

    if (modCount != expectedModCount)
        throw new ConcurrentModificationException();
…由谁来做检查

下面是代码中发生的情况:

  • 您可以创建一个
    HashMap
  • 您可以向其中添加一个条目
  • 开始一个迭代
  • hasNext
    为true,因此进入循环主体
  • next
    获取元素;此时,迭代器会记住其内部数据成员上的下一个元素应该是什么(名称混乱的
    next
    ),在这种情况下,由于映射中没有下一个元素,
    next
    数据成员被设置为
    null
    ,这意味着迭代已经完成
  • 你添加到地图上
  • 您的代码调用
    hasNext
    ,它看到
    next
    数据成员为
    null
    ,并返回
    false
  • 如果在开始循环之前映射中有两个元素而不是一个,则会出现异常(从
    next

    我以前认为这是一个bug,或者说几乎是一个bug,但这是一个相当模糊的领域,其他人也相当合理地认为它不是。文档没有明确说明迭代器的哪些方法将抛出异常,只是说明它将被抛出。文件还说,它只是在“尽力而为”的基础上抛出的,不能保证


    无论你是否认为这是一个bug,在这一点上都不太可能被更改,因为更改它的痛苦(破坏一些可能不应该依赖于此行为的现有代码)远远超过了好处(可能更“正确”)。

    迭代器可能抛出ConcurrentModificationException,但不能保证会

    从HashMap的javadoc:

    请注意,无法保证迭代器的快速失败行为 一般来说,不可能作出任何硬性保证 在存在非同步并发修改的情况下。快速失败 迭代器尽最大努力抛出ConcurrentModificationException 基础。因此,编写依赖于 关于其正确性的例外:的fail fast行为 迭代器只能用于检测bug

    试试这个:

      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());
    
    
        }
    
    Map m=newhashmap();
    m、 将(“a”、“a”);
    迭代器i=m.keySet().Iterator();
    while(i.hasNext()){
    m、 删除(“a”);
    System.out.println(i.next());
    }
    
    为什么这不是一个bug?@Raj:嗯,我认为这是一个bug。我用一些推理更新了答案,并对您的示例中发生的情况进行了更深入的解释。您的问题是在地图上迭代时调用
    m.put
    i
    是否应转到键
    dsad