java - 删除 ArrayList 时出现 Java ConcurrentModificationException
问题描述
当 ArrayList 的 Size 为 2 时,我们使用 foreach 循环执行删除操作,它打印最后一个元素,不抛出异常,
例如 :
ArrayList<String> a= new ArrayList<String>(Arrays.asList("abc","xyz"));
for(String i : a){
a.remove(i);
}
// a contains "xyz"
但是当我们将arrayList的大小增加到2以上,并执行操作时,它会显示concurrentModificationException。为什么它会表现出这种行为(它适用于 2 个元素,但不适用于 2 个以上)?
解决方案
这是实施的一个怪癖。
仅在尽力而为的基础上抛出异常,不能保证它会被抛出。
要了解原因,您需要了解增强的 for 循环是如何脱糖的:
for (String i : a) {
a.remove(i);
}
被编译成类似的东西:
Iterator<String> it = a.iterator();
while (it.hasNext()) {
String i = a.next();
a.remove(i);
}
接下来,迭代器的实现如下:
int idx = 0;
boolean hasNext() {
return idx < a.size();
}
Object next() {
checkForModification(); // throws exception if list has been modified.
return a.get(idx++);
}
因此,如果列表最初的大小为 2,则循环执行如下:
- 检查
hasNext()
:idx == 0
,并且0 < 2
为真,所以它返回真。 - 调用
next()
:retrievei = a.get(0)
、incrementidx
等idx == 1
。 i
从中删除a
。现在a.size() == 1
。
循环已执行一次。现在它再次执行:
- 检查
hasNext()
:idx == 1
,并且1 < 1
是假的,所以它返回假。
所以执行停止,不ConcurrentModificationException
。该列表仍然包含最初的第二项。
如果列表最初大于 2,则循环第二次执行(因为idx == 1
, 和size() == initial size() - 1
, 所以idx < initial size() - 1
),所以next()
将在remove()
. 该列表已被修改,因此checkForModification()
引发异常。
推荐阅读
- c# - 使用 Entity Framework Core C# 反序列化 JSON
- odoo-13 - Odoo 13 进口电子商务类别
- go - 查找 2 个语句之间的匹配百分比
- bash - lftp、stdout、stderr 和 SAP exec_protocol
- javascript - 使用 cookie 连接到 websocket
- mysql - 我是否正确使用“NOT IN”?
- c# - Unity2d:dontDestroyOnLoad 只工作一次吗?
- python - Python Sphinx:如何将代码嵌入到文档字符串中?
- arrays - 试图理解循环
- java - 在 NetBeans 中将 MySQL Workbench 数据库连接到 Java 应用程序