在预期时不抛出java.util.ConcurrentModificationException

时间:2014-07-27 11:53:27

标签: java exception

以下代码按预期抛出java.util.ConcurrentModificationException

   public void test(){
      ArrayList<String> myList = new ArrayList<String>();

      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);
         }
      }
   }

但是,以下代码抛出异常,而我希望抛出它:

   public void test(){
      ArrayList<String> myList = new ArrayList<String>();

      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)

问题:为什么第二段代码 NOT 抛出java.util.ConcurrentModificationException?

2 个答案:

答案 0 :(得分:17)

在实现中从ArrayList.iterator()返回的迭代器我们显然都只使用了对next()调用中结构修改的检查,而不是调用hasNext() }。后者看起来像这样(在Java 8下):

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

所以在你的第二种情况下,迭代器“知道”它返回了两个元素,并且列表只有两个元素......所以hasNext()只返回false,而我们永远不会第三次打电话给next()

我认为这是一个实现细节 - 基本上检查不是那么严格。 hasNext()执行检查并在这种情况下抛出异常是完全合理的。

答案 1 :(得分:8)

还请注意ArrayList documentation summary的最后一段:

  

快速失败的迭代器抛出ConcurrentModificationException   尽力而为的基础。因此,编写程序是错误的   这取决于它的正确性:失败快速   迭代器的行为应仅用于检测错误。

如果您担心强制列表是只读的,请使用Collections.unmodifiableList方法,而不是检查ConcurrentModificationException,如上所述,不保证在所有相关情况下抛出。< / p>