【问题标题】:Old for-each loop works, new for-each loop gets ConcurrentModificationException旧的 for-each 循环有效,新的 for-each 循环获取 ConcurrentModificationException
【发布时间】:2015-11-10 07:22:35
【问题描述】:

据我了解,当您尝试编辑仍在迭代的列表时,您会收到 ConcurrentModificationException。

现在我不明白的是,为什么旧​​的 foreach 循环没有给出异常,而新的 foreach 循环有?

public void newForeachLoop() {
    for (Person person : list) {
        if (person.getPosition().equals(this.getPosition())) {
            list.remove(person);
        }
    }
}

public void oldForeachLoop() {
    for (int i = 0; i < list.size(); i++) {
        if (list.get(i).getPosition().equals(this.getPosition())) {
            list.remove(list.get(i));
        }
    }
}

【问题讨论】:

  • 是的,两个循环的用途完全相同。
  • oldForeachLoop 不使用迭代器。没有迭代器,修改列表没有问题。
  • @digidude 我试图写一些类似的东西,但你是第一个:) 实际上,我认为你应该用一些解释来回答你的评论
  • 澄清一下,您的代码中只有一个 for-each 循环。 “oldForeachLoop”只是一个简单的 for 循环。

标签: java loops exception foreach


【解决方案1】:

正如@SacJn 解释的那样,在通过iterator() 迭代时,您不能在List 中进行结构更改(例如添加或删除元素)。 iterator() 将检测到不一致并抛出ConcurrentModificationException。在 Java-8 中,有一种干净安全的方式来解决您的任务:

public void java8Solution() {
    list.removeIf(person -> person.getPosition().equals(this.getPosition()));
}

【讨论】:

    【解决方案2】:

    因为每个循环都是基于迭代器的,所以不能在迭代时从列表中删除一个元素。 您甚至可以尝试显式使用迭代器并删除元素。

        List<String> list= new ArrayList <String>;
        list.add("One");
        list.add("two");
        list.add("three");
    
        Iterator listItr = list.iterator () ;
        while ( listItr.hasNext() )
        {
          String countStr = itr.next();
          if ( countStr.equals ("two"))
              itr.remove(); //will not throw any exception
    
         //if you do it list.remove (countStr) //will throw exception 
        }  
    

    在迭代时使用索引从列表中删除一个元素,绝对不会抛出任何异常,但你需要特别注意它的长度被修改。甚至其他元素的索引也会受到您的操作的干扰。所以如果你照顾好这不是问题。

    【讨论】:

      【解决方案3】:

      在旧循环中,您使用列表迭代器,而是使用列表中对象的计数。

      在新循环中,您使用的是内置迭代器,它是该实例的指针。当您从列表中删除一个项目时,您正在修改该实例并重置迭代器,从而引发异常。

      【讨论】:

      • 那么您认为修改旧循环中的列表是不好的做法吗?
      • 就我个人而言,我不会修改我正在迭代的列表,我会将结果复制到另一个列表中。
      • 在调用 remove 后不需要继续迭代的情况如何?可以直接调用return吗?然后?还是将其全部添加到列表中是否更好?
      • 要使这个答案完整,您可以使用迭代器删除一个元素。请参阅迭代器接口文档。为此,您可以在实现可迭代的集合上调用迭代器方法。然后,您可以使用迭代器 next 方法通过调用 remove 的选项遍历集合。
      • 为什么不使用 CopyOnWriteArrayList? docs.oracle.com/javase/7/docs/api/java/util/concurrent/…
      猜你喜欢
      • 2015-11-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-11
      • 1970-01-01
      • 1970-01-01
      • 2014-10-19
      • 1970-01-01
      相关资源
      最近更新 更多