2

I am trying to add a key value pair to the hashmap inside the Iterator method.

But this is not giving me ConcurrentModificationException . Why?

Since Hashmap is failfast.

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

           }

If this is wrong, How i can produce ConcurrentModificationException ? Thanks.

Update: Just checked.

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

               }

This is giving me the exception.

4

3 回答 3

3

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

public final boolean hasNext() {
    return next != null;
}

... where(令人困惑!)这是迭代器类中的私有数据成员(不要与接口上的方法next混淆- 在我看来,调用该数据成员是一个非常糟糕的选择)。nextIteratornext

请注意,它不会检查并发修改。与从以下位置(间接)调用的代码进行对比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)。

我之前曾争论过这是一个错误,或者几乎是一个错误,但它是一个非常模糊的区域,而其他人则相当合理地认为它不是。文档没有具体说明哪些方法Iterator<E>会抛出异常,只是会抛出异常。文档还说它只是在“尽力而为”的基础上抛出的,不能保证。

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

于 2013-08-26T17:39:47.273 回答
0

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

来自 HashMap 的 javadoc:

请注意,不能保证迭代器的快速失败行为,因为一般来说,在存在不同步的并发修改的情况下,不可能做出任何硬保证。快速失败的迭代器会尽最大努力抛出 ConcurrentModificationException。因此,编写一个依赖于这个异常的正确性的程序是错误的:迭代器的快速失败行为应该只用于检测错误。

于 2013-08-26T17:39:50.270 回答
0

尝试这个:

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


    }
于 2013-08-26T17:43:43.703 回答