迭代 Hashmap 时如何得到 ConcurrentModificationException?

2024-04-17

我正在尝试将键值对添加到迭代器方法内的哈希映射中。

但这并没有给我ConcurrentModificationException . Why?

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

           }

如果这是错误的,我如何产生 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代码无法检测到这种情况。代码为HashMap的迭代器hasNext在Oracle的JDK7中是:

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

...哪里(令人困惑!)next是迭代器类中的私有数据成员(不要与next方法上的Iterator接口——在我看来,调用该数据成员next was a very糟糕的选择)。

请注意,它不会检查并发修改。与(间接)调用的这段代码进行对比Iterator#next:

    if (modCount != expectedModCount)
        throw new ConcurrentModificationException();

...哪个does做检查。

因此,您的代码中会发生以下情况:

  1. 你创建一个HashMap.
  2. 您向其中添加一项。
  3. 您开始迭代。
  4. hasNext是真的,所以你进入循环体。
  5. 您从以下位置获取元素next;此时,迭代器会记住其内部数据成员(名称容易混淆的next),在这种情况下,由于地图中没有下一个元素,因此next数据成员设置为null,表示迭代完成。
  6. 您添加到地图。
  7. 你的代码调用hasNext,这会看到next数据成员是null并返回false.

如果在开始循环之前地图中有两个元素而不是一个,那么您会得到异常(来自next).

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

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

迭代 Hashmap 时如何得到 ConcurrentModificationException? 的相关文章

随机推荐