该列表有一个名为的变量modCount
,这意味着“修改计数”。每当你打电话时remove
(或执行其他结构修改),它增加了modCount
.
如果您在不通知迭代器的情况下添加或删除元素,迭代器将无法跟踪其在列表中的位置。因此,作为安全检查,在迭代开始时,迭代器会记下modCount
,另存为expectedModCount
。当从迭代器读取每个项目时,迭代器会检查以确保modCount
仍然等于预期值,如果不等于则抛出异常。
通常,如果列表在迭代期间被不安全地修改,这将成功导致抛出异常。然而,在这种情况下这还不够,当if
语句已启用。阅读完您的代码后"World"
,该项目已被删除,因此列表现在包含["Hello", Good Evening"]
。迭代器仍然位于位置 1(现在包含"Good Evening"
)并且当它尝试读取下一个项目时,它发现它现在已经到达列表的末尾,所以它不费心去检查modCount
。因此,也不例外。
请注意中的警告ConcurrentModificationException 文档 http://docs.oracle.com/javase/8/docs/api/java/util/ConcurrentModificationException.html:“一般来说,在存在不同步并发修改的情况下不可能做出任何硬保证。快速失败操作会尽力抛出 ConcurrentModificationException。”
即使在这种情况下没有抛出异常,代码仍然是错误的。要在迭代时删除元素,必须使用迭代器自己的remove
method:
for (Iterator<String> it = list1.iterator(); it.hasNext();) {
String s = it.next();
if (s.equals("World")) {
it.remove();
}
}
这样,迭代器就知道列表已更改并且仍然可以正确迭代。
或者,您可以从列表的临时副本进行迭代:
for (String s : new ArrayList<>(list1)) {
if (s.equals("World")) {
list1.remove(...);
}
}
尽管在这个简单的情况下,您甚至不需要这样做;你可以写:
list1.remove("World");