我正在尝试将键值对添加到Iterator方法中的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");
}
如果这是错误的,我怎么能产生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");
}
这给了我例外。
答案 0 :(得分:3)
HashMap
代码执行的并发修改检查无法检测到这种情况。 Oracle JDK7中HashMap
的迭代器hasNext
的代码是:
public final boolean hasNext() {
return next != null;
}
...其中(令人困惑!)next
是迭代器类中的私有数据成员(不要与next
接口上的Iterator
方法混淆 - 到我的请注意,调用该数据成员next
是非常糟糕的选择。)
请注意,它不会检查并发修改。与({间})Iterator#next
:
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
... 做进行检查。
所以这是你的代码中发生的事情:
HashMap
。hasNext
是真的,所以你进入循环体。next
获得元素;此时,迭代器会记住下一个元素应该在其内部数据成员上的内容(容易引起混淆的next
),在这种情况下,因为地图中没有下一个元素,所以next
数据member设置为null
,表示迭代已完成。hasNext
,其中next
数据成员为null
并返回false
。如果你在开始循环之前在地图中有两个元素而不是一个,你就会得到异常(来自next
)。
我之前认为这是一个或几乎是一个错误,但它是一个非常模糊的领域,而其他人则相当合理地认为它不是。该文档没有具体说明Iterator<E>
的哪些方法会引发异常,只是它会被抛出。该文档还说它只是在“尽力而为”的基础上投入,但并不能保证。
无论是否认为这是一个错误,此时不太可能改变,因为改变它的痛苦(打破一些可能不应该依赖于这种行为的现有代码)远远超过了利益(可能是更“正确”)。
答案 1 :(得分:0)
迭代器可能抛出ConcurrentModificationException,但不保证。
来自HashMap的javadoc:
请注意,无法保证迭代器的快速失败行为 一般来说,不可能做出任何硬性保证 存在不同步的并发修改。快速失败 迭代器抛出ConcurrentModificationException就是尽力而为 基础。因此,编写一个依赖的程序是错误的 关于它的正确性的这个例外:快速失败的行为 迭代器应该只用于检测错误。
答案 2 :(得分: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());
}