java.util.ConcurrentModificationException在预期时不会抛出
以下代码抛出java.util.ConcurrentModificationException ,如预期的那样:
public void test(){ ArrayList myList = new ArrayList(); myList.add("String 1"); myList.add("String 2"); myList.add("String 3"); myList.add("String 4"); myList.add("String 5"); for(String s : myList){ if (s.equals("String 2")){ myList.remove(s); } } }
但是,以下代码不会抛出exception,而我希望抛出它:
public void test(){ ArrayList myList = new ArrayList(); myList.add("String 1"); myList.add("String 2"); myList.add("String 3"); for(String s : myList){ if (s.equals("String 2")){ myList.remove(s); } } }
区别在于第一个列表包含5个项目,而第二个列表包含3.使用的JVM是:
java version "1.8.0" Java(TM) SE Runtime Environment (build 1.8.0-b132) Java HotSpot(TM) 64-Bit Server VM (build 25.0-b70, mixed mode)
问题:为什么第二段代码不会抛出java.util.ConcurrentModificationException?
在实现中从ArrayList.iterator()
返回的迭代器我们显然都只使用对next()
调用的结构修改检查, 而不是对hasNext()
调用。 后者看起来像这样(在Java 8下):
public boolean hasNext() { return cursor != size; }
所以在你的第二种情况下,迭代器“知道”它返回了两个元素,并且列表只有两个元素…所以hasNext()
只返回false,我们永远不会第三次调用next()
。
我认为这是一个实现细节 – 基本上检查没有尽可能严格。 在这种情况下, hasNext()
执行检查并抛出exception是完全合理的。
另请注意ArrayList文档摘要的最后一段:
失败快速迭代器会尽最大努力抛出
ConcurrentModificationException
。 因此,编写依赖于此exception的程序以确保其正确性是错误的: 迭代器的快速失败行为应该仅用于检测错误。
如果您担心强制列表是只读的,请使用Collections.unmodifiableList
方法,而不是检查ConcurrentModificationException,如上所述,不保证在所有相关情况下抛出。