为什么不在此处抛出 ConcurrentModificationException?

Why isn't ConcurrentModificationException being thrown here?

看看这段代码:

ArrayList al = new ArrayList();
al.add("AA");
al.add("AB");
al.add("AC");
Iterator it = al.iterator();
while(it.hasNext()){
String s = (String)it.next();
if(s.equals("AB")){
al.remove(1);
}
}

因为 ArrayList 有快速失败迭代器,很明显,给定的 ArrayList 不是由固定大小的数组组成的(这将呈现 remove() 方法不可用 ),上面的代码应该抛出 ConcurrentModificationException 但是,是的,它没有。

此外,如果我在循环中插入一条打印语句(作为第一条语句),它表明循环没有进行第三次迭代并且正常退出。

我知道这听起来太愚蠢了,但我能想到 错误 的唯一原因是元素的删除发生在之后 ] 该元素已被迭代器遍历。但事实并非如此,因为 modificationCount 仍会通过删除进行修改,因此它必须抛出异常。

正在做

while(it.hasNext()){
it.next();
al.remove(1);
}

虽然会抛出 ConcurrentModificationException。

有什么见解吗?

这是因为 hasNext() 方法没有检查 modCount:

public boolean hasNext() {
    return cursor != size;
}

因此,在调用remove(1)后,列表的大小将与光标一样为2,而hasNext()将return为false。 next() 方法永远不会被调用并且 modCount 永远不会被检查。

如果您在迭代之前将第四个元素添加到列表中,您将得到与第二个示例类似的异常。

并发修改的检查仅在迭代器的 next() 调用期间发生,而不是在其 hasNext() 调用内发生,如 中所述。

java documentation for ArrayList明确规定,

Fail-fast iterators throw ConcurrentModificationException on a best-effort basis. Therefore, it would be wrong to write a program that depended on this exception for its correctness: the fail-fast behavior of iterators should be used only to detect bugs.

因此,在迭代时修改集合是一种错误的编程习惯。