我正在尝试将键值对添加到迭代器方法内的哈希映射中。
但这并没有给我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做检查。
因此,您的代码中会发生以下情况:
- 你创建一个
HashMap
.
- 您向其中添加一项。
- 您开始迭代。
-
hasNext
是真的,所以你进入循环体。
- 您从以下位置获取元素
next
;此时,迭代器会记住其内部数据成员(名称容易混淆的next
),在这种情况下,由于地图中没有下一个元素,因此next
数据成员设置为null
,表示迭代完成。
- 您添加到地图。
- 你的代码调用
hasNext
,这会看到next
数据成员是null
并返回false
.
如果在开始循环之前地图中有两个元素而不是一个,那么您会得到异常(来自next
).
我之前曾认为这是或几乎是一个错误,但这是一个相当模糊的领域,而其他人则相当合理地认为它不是。文档没有具体说明哪些方法Iterator<E>
会抛出异常,只是它会被抛出。该文档还表示,它只是在“尽力而为”的基础上抛出,并不能保证。
无论人们是否认为这是一个错误,此时都不太可能对其进行更改,因为更改它的痛苦(破坏一些可能不应该依赖此行为的现有代码)远远超过了好处(可能更“正确”) ”)。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)