在Java中调用foreach循环中的remove

这个问题在这里已经有了答案:

  • 循环访问集合,避免在循环21中删除时出现ConcurrentModificationException

  • 在迭代时要安全地从集合中移除,你应该使用Iterator。

    例如:

    List<String> names = ....
    Iterator<String> i = names.iterator();
    while (i.hasNext()) {
       String s = i.next(); // must be called before you can call i.remove()
       // Do something
       i.remove();
    }
    

    从Java文档:

    这个类的迭代器和listIterator方法返回的迭代器是快速失败的:如果在迭代器创建后的任何时候,结构上都会修改列表,除了通过迭代器自己的remove或add方法以外,迭代器将抛出ConcurrentModificationException。 因此,面对并发修改,迭代器快速而干净地失败,而不是在将来某个未确定的时间冒着任意的,非确定性的行为风险。

    也许很多新手不清楚的是,使用for / foreach构造迭代列表会隐式创建一个必须无法访问的迭代器。 这个信息可以在这里找到


    你不想这样做。 它可能导致取决于集合的未定义行为。 你想直接使用Iterator。 尽管每个构造都是语法糖,并且实际上正在使用迭代器,但它会将它从代码中隐藏起来,因此无法访问它来调用Iterator.remove

    如果除了通过调用此方法以外的任何其他方式进行迭代时修改了底层集合,则未指定迭代器的行为。

    请写下你的代码:

    List<String> names = ....
    Iterator<String> it = names.iterator();
    while (it.hasNext()) {
    
        String name = it.next();
        // Do something
        it.remove();
    }
    

    请注意,代码调用Iterator.remove ,而不是List.remove

    附录:

    即使您要删除尚未迭代的元素,仍然不想修改集合,然后使用Iterator 。 它可能会以令人惊讶的方式修改集合,并影响Iterator未来操作。


    “增强for循环”的java设计是不将迭代器公开给代码,但安全删除一个项目的唯一方法是访问迭代器。 所以在这种情况下,你必须做到老派:

     for(Iterator<String> i = names.iterator(); i.hasNext();) {
           String name = i.next();
           //Do Something
           i.remove();
     }
    

    如果在真正的代码中增强的for循环真的值得,那么您可以将这些项添加到临时集合中,并在循环之后调用列表中的removeAll。

    编辑(补充):不,在iterator.remove()方法之外以任何方式更改列表时都会导致问题。 解决此问题的唯一方法是使用CopyOnWriteArrayList,但这确实是用于并发问题。

    最便宜的(按照代码行)删除重复项的方法是将列表转储到LinkedHashSet(如果需要,然后返回到列表中)。 这可以在删除重复项时保留插入顺序。

    链接地址: http://www.djcxy.com/p/8835.html

    上一篇: Calling remove in foreach loop in Java

    下一篇: Pattern for modifying knockout observable on parent from child view model