2

看看这个小代码:

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 。

有什么见解吗?

4

2 回答 2

2

发生这种情况是因为该hasNext()方法不检查modCount

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

所以,调用 后remove(1),列表的大小将和光标一样为 2,并hasNext()返回 false。该next()方法永远不会被调用,modCount也永远不会被检查。

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

于 2017-07-29T08:40:28.903 回答
0

并发修改的检查仅在 Iterator 的next()调用期间发生,而不是在其hasNext()调用中发生,如Bubletan 的回答中所述。

java 文档ArrayList明确指出,

快速失败的迭代器会尽最大努力抛出 ConcurrentModificationException。因此,编写一个依赖于这个异常的正确性的程序是错误的:迭代器的快速失败行为应该只用于检测错误。

因此,在迭代时修改集合是错误的编程实践。

于 2017-07-29T09:10:51.380 回答