[英]How I can get ConcurrentModificationException while iterating Hashmap?
I am trying to add a key value pair to the hashmap inside the Iterator method. 我试图将一个键值对添加到Iterator方法内的哈希图中。
But this is not giving me ConcurrentModificationException
. 但这并没有给我
ConcurrentModificationException
。 Why? 为什么?
Since Hashmap is failfast. 由于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");
}
If this is wrong, How i can produce ConcurrentModificationException ? 如果这是错误的,我如何产生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. 这给了我一个例外。
It happens that the concurrent modification check done by the HashMap
code fails to detect this situation. 碰巧,由
HashMap
代码完成的并发修改检查无法检测到这种情况。 The code for HashMap
's iterator's hasNext
in Oracle's JDK7 is: Oracle JDK7中
HashMap
的迭代器hasNext
的代码是:
public final boolean hasNext() {
return next != null;
}
...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). ...在哪里(令人困惑!)
next
是迭代器类中的私有数据成员(不要与Iterator
接口上的next
方法相混淆-在我看来,将数据成员称为next
是一个非常糟糕的选择)。
Note that it doesn't do the check for concurrent modifications. 请注意,它不会检查并发修改。 Contrast with this code that is called (indirectly) from
Iterator#next
: 与此代码(从
Iterator#next
间接调用)对比:
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
...which does do the check. ......这确实做检查。
So here's what happens in your code: 因此,这就是您的代码中发生的情况:
HashMap
. HashMap
。 hasNext
is true, so you go into the body of your loop. hasNext
是真的,因此您进入了循环的主体。 next
; 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. next
),在这种情况下,由于映射中没有下一个元素,因此next
数据成员被设置为null
,这意味着迭代完成。 hasNext
, which sees the next
data member is null
and returns false
. hasNext
,它看到next
数据成员为null
并返回false
。 If you had two elements in the map before starting your loop instead of one, you'd get the exception (from next
). 如果在开始循环之前在映射中有两个元素而不是一个,则将获得异常(来自
next
)。
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. 我以前曾说过,这是一个bug,或者几乎是一个bug,但这是一个非常模糊的领域,而其他人则相当合理地认为不是。 The documentation doesn't say specifically which methods of
Iterator<E>
will throw the exception, just that it will get thrown. 该文档没有具体说明
Iterator<E>
哪些方法将引发异常,而只是引发该异常。 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"). 无论是否认为它是一个错误,在这一点上都不太可能更改,因为更改它的痛苦(破坏一些本不应该依赖此行为的现有代码)远远超过了好处(可能更“正确”) “)。
The iterator may throw ConcurrentModificationException but is not guaranteed to. 迭代器可能会抛出ConcurrentModificationException,但不能保证如此。
From the javadoc of HashMap: 从HashMap的javadoc中:
Note that the fail-fast behavior of an iterator cannot be guaranteed as it is, generally speaking, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification.
请注意,迭代器的快速失败行为无法得到保证,因为通常来说,在存在不同步的并发修改的情况下,不可能做出任何严格的保证。 Fail-fast iterators throw ConcurrentModificationException on a best-effort basis.
快速失败的迭代器会尽最大努力抛出ConcurrentModificationException。 Therefore, it would be wrong to write a program that depended on this exception for its correctness: the fail-fast behavior of iterators should be used only to detect bugs.
因此,编写依赖于此异常的程序以确保其正确性是错误的:迭代器的快速失败行为应仅用于检测错误。
Try this: 尝试这个:
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.