看看这一小段代码:
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
但是是的,它没有。
此外,如果我在循环中插入一个 print 语句(作为第一个语句(,它表明循环不会迭代第三次并且它优雅地退出。
我知道这听起来太愚蠢了,但我能错误地想到的唯一原因是元素的删除发生在元素被迭代器遍历之后。但情况并非如此,因为modificationCount
仍然通过删除进行修改,因此它必须抛出异常。
只是做
while(it.hasNext()){
it.next();
al.remove(1);
}
不过确实抛出了 ConcurrentModificationException。
有什么见解吗?
发生这种情况是因为hasNext()
方法不检查modCount
:
public boolean hasNext() {
return cursor != size;
}
因此,在调用remove(1)
后,列表的大小将像光标一样为 2,并且hasNext()
将返回 false。永远不会调用next()
方法,也永远不会检查modCount
方法。
如果在迭代之前将第四个元素添加到列表中,则获得与第二个示例类似的异常。
并发修改的检查仅在迭代器的next()
调用期间发生,但不在其hasNext()
调用内发生,如Bubletan的答案中所述。
ArrayList
的 Java 文档明确指出,
Fail-fast 迭代器在 尽力而为。因此,编写程序是错误的 这取决于此异常的正确性:快速故障 迭代器的行为应仅用于检测错误。
因此,在迭代集合时修改集合是一种错误的编程做法。