它不会抛出exceptionConcurrentModificationException

我有下面的代码,我希望它抛出一个ConcurrentModificationException ,但它运行成功。 为什么会这样?

 public void fun(){ List lis = new ArrayList(); lis.add(1); lis.add(2); for(Integer st:lis){ lis.remove(1); System.out.println(lis.size()); } } public static void main(String[] args) { test t = new test(); t.fun(); } 

List上的remove(int)方法删除指定位置的元素。 在开始循环之前,列表如下所示:

 [1, 2] 

然后在列表上启动一个迭代器:

 [1, 2] ^ 

你的for循环然后删除位置1的元素 ,即数字2:

 [1] ^ 

迭代器在下一个隐含的hasNext()调用中返回false ,循环终止。

如果向列表中添加更多元素,则会收到ConcurrentModificationException 。 然后隐含的next()将抛出。

请注意,来自JCF的Javadoc for ArrayList

请注意,迭代器的快速失败行为无法得到保证,因为一般来说,在存在不同步的并发修改时,不可能做出任何硬性保证。 失败快速迭代器会尽最大努力抛出ConcurrentModificationException 。 因此,编写依赖于此exception的程序以确保其正确性是错误的: 迭代器的快速失败行为应该仅用于检测错误

这实际上可能是Oracle ArrayList迭代器实现中的一个错误; hasNext()不检查修改:

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

它不会抛出ConcurrentModificationException,因为正如vandale所说,迭代器只检查next()上的编码。 这是ArrayList返回的Iterator实例的一部分:

  public boolean hasNext() { return cursor != size; } @SuppressWarnings("unchecked") public E next() { checkForComodification(); int i = cursor; if (i >= size) throw new NoSuchElementException(); Object[] elementData = ArrayList.this.elementData; if (i >= elementData.length) throw new ConcurrentModificationException(); cursor = i + 1; return (E) elementData[lastRet = i]; } 

hasNext()只是查看光标是否指向列表的最后一个索引。 它不检查列表是否被修改。 因此,您没有得到ConcurrentModificationException,它只是停止迭代。

如果您有3个列表,如:

 lis.add(1); lis.add(2); lis.add(3); 

在你的情况下你会得到ConcurrentModificationException。 PS:我试过这个!

因为您没有删除1,所以在1处remove(int)元素。( remove(int) vs remove(Object)

迭代器只会检查对next()而不是hasNext() ,并且在调用hasNext()之后循环将退出,因为你已经删除了2,列表只有一个长,因此退出。

问题的要点是,如ArrayListConcurrentModificationException

请注意,迭代器的快速失败行为无法得到保证,因为一般来说,在存在不同步的并发修改时,不可能做出任何硬性保证。 失败快速迭代器会尽最大努力抛出ConcurrentModificationException。

现在来自ArrayList返回的Iterator的代码示例:

  public boolean hasNext() { return cursor != size; } public E next() { checkForComodification();  return ; }  final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); } 

正如您可以清楚地看到的,在ArrayList的情况下,“尽力而为”是在调用next()检查修改而不是在调用getNext() 。 你的循环终止而没有第二次调用next() ,因此没有exception。 如果你有3个元素开始,或添加一个元素,它将失败。 另外值得注意的是,如果使用reflection修改数组列表而不更新modCount变量(顽皮…),则根本不会抛出exception。 modCount也不是volatile,它再次显示它是唯一的尽力而且无法保证,因为迭代器可能无论如何都看不到最新的值。

在这个循环中:

  for(Integer st:lis){ lis.remove(1); System.out.println(lis.size()); } 

你只是不断地从矩阵中删除索引为1的元素,甚至没有关注st中的内容。 所以这个循环和每次迭代都会尝试删除索引为1的项目。对此循环进行Concurent修改:

  for(Integer st:lis){ lis.remove(st); System.out.println(lis.size()); } 

列表中只有2个条目。 因此,循环只运行一次,因为您删除了一个条目。

如果修改了列表,则会抛出ConcurrentModificationException,并再次尝试对其执行某些操作。 但在对它进行任何操作之前,我们已经不在循环中,因此也不例外。 尝试在列表中添加另一个条目并运行将抛出exception的程序。