在 0 索引处放入 HashMap 会导致 ConcurrentModificationException
Putting into HashMap at 0 index is causing ConcurrentModificationException
我有一个简单的HashMap
算法:
HashMap<Integer, Integer> map = new HashMap<>();
map.put(1, 1);
map.put(2, 2);
map.put(3, 3);
Iterator<Integer> it = map.keySet().iterator();
while(it.hasNext()) {
Integer key = it.next();
if (key.equals(2)) {
map.put(1, 2);
}
}
这工作正常。 但是当我将条件体修改为:
if (key.equals(2)) {
map.put(0, 2); // changed index '1' to '0'
}
它总是抛出 java.util.ConcurrentModificationException
。对于小于 0
.
的键值,也会发生同样的情况
我错过了什么?
编辑
似乎如果我将删除第三个 Map
元素:
map.put(1, 1);
map.put(2, 2);
// map.put(3, 3);
工作正常
您在迭代期间更改了地图的大小,这导致了异常。请记住,抛出异常的不是 put
操作,而是尝试通过迭代器通过 Iterator#next
获取下一个元素
在您的情况下,如果您“扩展”了地图,迭代器将在 next()
上抛出异常。但是,如果它是在最后一次迭代中完成的,则 hasNext
returns 为 false。这将导致跳过 next()
调用并且不会抛出异常。
只对小于0的键不相关
首先它与 map.put(1, 2); 一起工作,因为在这里您没有向地图添加新项目,您只是将现有值替换为另一个。
但是,如果您尝试添加任何具有新索引的新项目(例如您的示例中的 0,但可以有任何新索引,例如 4、5、6,....),您总是会得到 java.util.ConcurrentModificationException.
所以你不能在迭代器中添加新项目。
参考Javadoc(重点加):
The iterators returned by all of this class's "collection view methods" are fail-fast: if the map is structurally modified at any time after the iterator is created, in any way except through the iterator's own remove method, the iterator will throw a ConcurrentModificationException. Thus, in the face of concurrent modification, the iterator fails quickly and cleanly, rather than risking arbitrary, non-deterministic behavior at an undetermined time in the future.
结构修改前面定义为:
A structural modification is any operation that adds or deletes one or more mappings; merely changing the value associated with a key that an instance already contains is not a structural modification.
所以:
map.put(1, 2);
不是结构修改,因为键1
已经在map中了。您所做的只是更改与之关联的值。没有 ConcurrentModificationException
被抛出。
map.put(0, 2);
是结构修改,因为键0
不在映射中。因此,抛出 ConcurrentModificationException
。
我有一个简单的HashMap
算法:
HashMap<Integer, Integer> map = new HashMap<>();
map.put(1, 1);
map.put(2, 2);
map.put(3, 3);
Iterator<Integer> it = map.keySet().iterator();
while(it.hasNext()) {
Integer key = it.next();
if (key.equals(2)) {
map.put(1, 2);
}
}
这工作正常。 但是当我将条件体修改为:
if (key.equals(2)) {
map.put(0, 2); // changed index '1' to '0'
}
它总是抛出 java.util.ConcurrentModificationException
。对于小于 0
.
我错过了什么?
编辑
似乎如果我将删除第三个 Map
元素:
map.put(1, 1);
map.put(2, 2);
// map.put(3, 3);
工作正常
您在迭代期间更改了地图的大小,这导致了异常。请记住,抛出异常的不是 put
操作,而是尝试通过迭代器通过 Iterator#next
在您的情况下,如果您“扩展”了地图,迭代器将在 next()
上抛出异常。但是,如果它是在最后一次迭代中完成的,则 hasNext
returns 为 false。这将导致跳过 next()
调用并且不会抛出异常。
只对小于0的键不相关
首先它与 map.put(1, 2); 一起工作,因为在这里您没有向地图添加新项目,您只是将现有值替换为另一个。
但是,如果您尝试添加任何具有新索引的新项目(例如您的示例中的 0,但可以有任何新索引,例如 4、5、6,....),您总是会得到 java.util.ConcurrentModificationException.
所以你不能在迭代器中添加新项目。
参考Javadoc(重点加):
The iterators returned by all of this class's "collection view methods" are fail-fast: if the map is structurally modified at any time after the iterator is created, in any way except through the iterator's own remove method, the iterator will throw a ConcurrentModificationException. Thus, in the face of concurrent modification, the iterator fails quickly and cleanly, rather than risking arbitrary, non-deterministic behavior at an undetermined time in the future.
结构修改前面定义为:
A structural modification is any operation that adds or deletes one or more mappings; merely changing the value associated with a key that an instance already contains is not a structural modification.
所以:
map.put(1, 2);
不是结构修改,因为键1
已经在map中了。您所做的只是更改与之关联的值。没有ConcurrentModificationException
被抛出。map.put(0, 2);
是结构修改,因为键0
不在映射中。因此,抛出ConcurrentModificationException
。