如果我使用Iterator.remove()
,一切都很好。如果我使用ArryaList.remove()
,我总是收到错误java.util.ConcurrentModificationException
。
谁能指出原因?
如果我使用Iterator.remove()
,一切都很好。如果我使用ArryaList.remove()
,我总是收到错误java.util.ConcurrentModificationException
。
谁能指出原因?
javadocs 说明了一切:
当这种修改是不允许的时,检测到对象的并发修改的方法可能会抛出此异常。
例如,通常不允许一个线程在另一个线程对其进行迭代时修改 Collection。一般来说,在这些情况下,迭代的结果是不确定的。如果检测到此行为,某些迭代器实现(包括 JRE 提供的所有通用集合实现的那些)可能会选择抛出此异常。这样做的迭代器被称为快速失败迭代器,因为它们快速而干净地失败,而不是在未来不确定的时间冒着任意的、非确定性的行为的风险。
您正在修改一个集合并同时对其进行迭代。
基本上是因为它就是这样设计的。如果从列表中删除一个元素,迭代器不知道它,当它尝试访问列表中的另一个元素时,列表已更改并引发错误。但是,如果您通过迭代器删除一个元素,那么迭代器就会知道删除,对其数据结构进行适当的调整,然后继续。
所以完全来自文档
当这种修改是不允许的时,检测到对象的并发修改的方法可能会抛出此异常。
例如,通常不允许一个线程在另一个线程对其进行迭代时修改 Collection。一般来说,在这些情况下,迭代的结果是不确定的。如果检测到此行为,某些迭代器实现(包括 JRE 提供的所有通用集合实现的那些)可能会选择抛出此异常。这样做的迭代器被称为快速失败迭代器,因为它们快速而干净地失败,而不是在未来不确定的时间冒着任意的、非确定性的行为的风险。
如果在迭代列表时需要删除元素,则应始终使用迭代器。
例如
List<String> list = //...
//...
Iterator<String> iter = list.iterator();
while(iter.hasNext()) {
String str = itr.next();
//...
if(/* ... */) {
iter.remove(str);
}
}
这是在迭代列表时从列表中删除元素的最安全方法。
注意:您不应该执行以下操作:
List<String> list = //...
//...
for(String str : list) {
if(/* ... */) {
list.remove(); // <-- should not do this
}
}
大多数情况下,您最终会出现在ConcurrentModificationException
. 增强的 for 循环在底层使用了迭代器。而且您正在手动从列表中删除元素,而不是通过迭代器。这就是为什么你得到那个例外。