2017-07-29 88 views
3

看看这个小片的代码:为什么不在这里引发ConcurrentModificationException?

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中具有快速失败迭代,并清楚地,这将使得remove()方法不可用的给定的ArrayList不是由固定大小的阵列(),上面的代码应该抛出ConcurrentModificationException,但是,它没有。另外,如果我在循环中插入一条打印语句(作为第一条语句),它将显示循环不会第三次迭代,并且它会优雅地退出。

我知道这听起来太傻,但我能想到的虚假的唯一原因是去除元素的发生后的元素已遍历的迭代器的事实。但是,情况并非如此,因为modificationCount仍然通过删除进行修改,因此它必须抛出异常。

只是做

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

也不过抛出ConcurrentModificationException。

任何见解?谢谢!

回答

2

这是因为该hasNext()方法不检查modCount

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

因此,呼吁remove(1)后,该列表的大小为2就像光标,hasNext()将返回false。永远不会调用next()方法,并且不会检查modCount

如果在迭代之前将第四个元素添加到列表中,则会像第二个示例一样获得异常。

+0

喜欢精确,简短和健康的答案!非常感谢。 –

0

并发修改检查仅发生在迭代器的next()调用中,但不在hasNext()调用中,如Bubletan's answer中所述。

java documentation for ArrayList明确规定,

快速失败的迭代器抛出 尽力而为的基础上ConcurrentModificationException的。因此,编写一个程序 是错误的,这个程序依赖于这个例外的正确性:迭代器的失败 - 快速 行为应该只用于检测错误。

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

+0

尽我所能处理的所有执行过程中,一个非常简单的流程中的变化仍未被发现,这是否尽力而为?我曾经相信有一些其他类型的信号处理线程会照顾到修改。从你告诉我的情况来看,如果我在使用迭代器遍历时删除最后一个元素,那么由于缺少next()调用,将不会抛出异常,不是吗? –

+0

布布尔坦的答案清除了所有。它真的不应该被称为尽力而为的基础:D谢谢! –