如何在迭代Hashmap时获取ConcurrentModificationException? [英] How I can get ConcurrentModificationException while iterating Hashmap?

查看:86
本文介绍了如何在迭代Hashmap时获取ConcurrentModificationException?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将一个键值对添加到Iterator方法内的哈希图中.

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

但这并没有给我ConcurrentModificationException.为什么?

But this is not giving me ConcurrentModificationException . Why?

由于Hashmap速度很快.

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

           }

如果这是错误的,我如何产生ConcurrentModificationException? 谢谢.

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

更新:刚刚检查.

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的代码是:

It happens that the concurrent modification check done by the HashMap code fails to detect this situation. The code for HashMap's iterator's hasNext in Oracle's JDK7 is:

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

...在哪里(令人困惑!),next是迭代器类中的私有数据成员(不要与Iterator接口上的next方法混淆),在我看来,数据成员next非常的错误选择).

...where (confusingly!) that next is a private data member in the iterator class (not to be confused with the next method on the Iterator interface — to my mind, calling that data member next was a very poor choice).

请注意,它不会检查并发修改.与此代码(从Iterator#next间接调用)相反:

Note that it doesn't do the check for concurrent modifications. Contrast with this code that is called (indirectly) from Iterator#next:

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

...执行 的检查.

这就是您的代码中发生的事情:

So here's what happens in your code:

  1. 您创建一个HashMap.
  2. 您向其中添加一个条目.
  3. 您开始迭代.
  4. hasNext是真的,因此您进入了循环的正文.
  5. 您从next获取元素;此时,迭代器会记住下一个元素应在其内部数据成员上的名称(容易混淆的next),在这种情况下,由于映射中没有下一个元素,因此将next数据成员设置为null,表示迭代已完成.
  6. 您添加到地图上.
  7. 您的代码调用hasNext,该代码会看到next数据成员为null并返回false.
  1. You create a HashMap.
  2. You add one entry to it.
  3. You begin an iteration.
  4. hasNext is true, so you go into the body of your loop.
  5. You get the element from next; at this point, the iterator remembers what the next element should be on its internal data member (the confusingly-named next), and in this case since there's no next element in the map, that next data member is set to null, meaning that the iteration is complete.
  6. You add to the map.
  7. Your code calls hasNext, which sees the next data member is null and returns false.

如果在开始循环之前在映射中有两个元素而不是一个元素,则会得到异常(来自next).

If you had two elements in the map before starting your loop instead of one, you'd get the exception (from next).

我以前曾经说过,这是一个错误,或者几乎是一个错误,但这是一个相当模糊的领域,而其他人则相当合理地认为并非如此.该文档没有具体说明Iterator<E>的哪些方法将引发该异常,只是会引发该异常.该文档还说,这只是出于尽力而为"的原则,不能保证.

I've previously argued this is, or is very nearly, a bug, but it's a pretty fuzzy area, and others have argued quite reasonably that it isn't. The documentation doesn't say specifically which methods of Iterator<E> will throw the exception, just that it will get thrown. The documentation also says it's only thrown on a "best effort" basis, it's not guaranteed.

无论是否认为它是一个错误,在这一点上都不太可能被更改,因为更改它的痛苦(破坏一些本不应该依赖此行为的现有代码)的好处远大于其好处(可能是更多正确").

Whether one considers this a bug or not, it's unlikely to be changed at this point, as the pain of changing it (breaking some existing code that probably shouldn't have relied on this behavior) far outweighs the benefit (possibly being more "correct").

这篇关于如何在迭代Hashmap时获取ConcurrentModificationException?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆