注意:这不是许多问题的重复,这些问题询问如何在迭代过程中从地图上删除项目。
在使用哈希映射迭代器从映射中删除项目时,遇到了一些令人惊讶的边缘情况。
以下代码与a一起崩溃ConcurrentModificationException
。
Map<Integer, Integer> m = new HashMap<>();
m.put(1, 1);
m.put(2, 2);
m.put(3, 3);
for (Iterator<Map.Entry<Integer, Integer>> iterator = m.entrySet().iterator(); iterator.hasNext(); ) {
Map.Entry<Integer, Integer> e = iterator.next();
if (e.getKey() == 2) {
iterator.remove();
}
m.remove(2); // This causes the crash
}
毫不奇怪,以下代码不会:
Map<Integer, Integer> m = new HashMap<>();
m.put(1, 1);
m.put(2, 2);
m.put(3, 3);
for (Iterator<Map.Entry<Integer, Integer>> iterator = m.entrySet().iterator(); iterator.hasNext(); ) {
Map.Entry<Integer, Integer> e = iterator.next();
if (e.getKey() == 2) {
iterator.remove();
}
m.remove(4); // No crash here
}
但是,以下代码也不会崩溃:
Map<Integer, Integer> m = new HashMap<>();
m.put(2, 2);
m.put(3, 3);
for (Iterator<Map.Entry<Integer, Integer>> iterator = m.entrySet().iterator(); iterator.hasNext(); ) {
Map.Entry<Integer, Integer> e = iterator.next();
if (e.getKey() == 2) {
iterator.remove();
}
m.remove(2); // Also no crash?
}
第一个示例和第三个示例之间的唯一区别是删除了<1,1>条目。为什么调用Map.remove有时只会崩溃?该标准在任何地方都有规定吗?
第一个示例抛出a,ConcurrentModificationException
因为您正在remove
地图的迭代期间调用该方法。事件的顺序是这样。
next()
以检索条目(1,1)。关键不是2
,所以不要打电话iterator.remove()
。2
直接致电即可从地图中删除带有键的条目m.remove(2)
。这将更改内部修改计数,该计数Iterator
期望保持不变。next()
以检索下一个条目。映射中的修改计数不再与Iterator
创建时所指出的预期修改计数匹配,因此将ConcurrentModificationException
引发a。最后一个示例不再抛出它,因为remove(2);
它不再起作用。
next()
以检索条目(2,2)。关键是2
,因此致电iterator.remove()
,删除条目。这具有修改迭代器的预期修改计数以匹配映射的修改计数的效果。调用m.remove(2)
无效,因为该键2
不再存在于地图中。next()
以检索条目(3,3)。映射中的修改计数与指示的预期修改计数匹配Iterator
,因此不会ConcurrentModificationException
抛出任何异常。关键不是2
,所以iterator.remove()
不被调用。调用m.remove(2)
无效,因为该键2
在地图中不存在。请注意,以上事件序列对于JavaHashMap
迭代其条目的当前方式有效。密钥碰巧是按顺序检索的。通常,对于任何范围的有效整数键,都不能保证按顺序检索这些键。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句