【问题标题】:Foreach against for(int...) loop - why does foreach raises exceptions when removing elements? [duplicate]Foreach 针对 for(int...) 循环 - 为什么在删除元素时 foreach 会引发异常? [复制]
【发布时间】:2013-05-22 19:24:30
【问题描述】:

我想知道为什么我不能从列表中删除元素,当我使用 foreach 循环迭代它时:

List<Object> objects = new ArrayList<Object>();
Object one = new Object();
Object two = new Object();
Object three = new Object(); 

objects.add(one);
objects.add(two);
objects.add(three);

然后删除以下元素:

foreach(Object o : objects){
  objects.remove(three); //I know that o is my current object
}

似乎 foreach 循环不允许删除循环队列中“仍然”的对象。我说的对吗?

为什么 for-int-loop 不关心这个?在这个循环中,我可以轻松移除仍在循环中的对象。

谢谢

【问题讨论】:

    标签: java for-loop foreach


    【解决方案1】:

    嗯,最初这个问题被标记为 C#,现在被删除了。然而……

    如果你从集合中移除一个元素,for/loop 并不关心。 如果在前进的过程中删除元素,则在删除元素之后索引元素会出现问题,因为索引不再匹配您的下一个元素。 只有以相反的顺序循环(从最后一个元素到第一个元素),才能避免 for/loop 出现问题

    foreach 在内部也遇到了同样的问题。枚举器保持元素的Current位置,如果删除元素然后前进到Next位置,Current索引器不会指向删除后的元素,而是指向元素的第二位置删除后。

    例如:

    假设一个由“birds”、“animals”和“fishes”组成的字符串集合

    • 在 foreach 开始时,内部电流为 0(指向“鸟”)
    • 您删除了“birds”,因此“animals”的索引为 0(Current 仍指向该位置)
    • 您前进到下一个元素(Current=1,指向“鱼”)
    • Next 前进将无一例外地退出循环。

    foreach 的设计不允许这种情况。

    【讨论】:

      【解决方案2】:

      就Java而言,答案在javadoc(重点是我的):

      此类的 iterator 和 listIterator 方法返回的迭代器是快速失败的:如果在创建迭代器后的任何时候对列表进行结构修改,除了通过迭代器自己的 remove 或 add 方法之外的任何方式,迭代器将抛出并发修改异常。因此,面对并发修改,迭代器快速而干净地失败,而不是在未来不确定的时间冒任意的、非确定性的行为。

      【讨论】:

        【解决方案3】:

        至少对于 Java,您是正确的:问题是用于遍历列表中元素的迭代器不允许修改。它将抛出 ConcurrentModificationException。引用java.util.ArrayList的Java API javadoc

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

        替代方法是使用允许此类修改的迭代器,而不是 ArrayList 的默认值,或者显式创建迭代器,而不是使用 foreach 循环,并使用它在迭代列表时更改内容的方法.

        【讨论】:

          【解决方案4】:

          Calling remove in foreach loop in Java,一般使用Iterator,如果有更多元素用hasNext检查

          【讨论】:

          • 谢谢蒂姆,我不知道为什么我不能使用链接
          • 哦,在问之前我没看过这个帖子。谢谢!
          • 这应该是一个重复的标志,而不是一个答案,因为几乎没有任何合适的内容。
          • 抱歉,我是新手
          猜你喜欢
          • 2019-10-17
          • 1970-01-01
          • 1970-01-01
          • 2012-02-15
          • 2021-11-06
          • 2014-10-29
          • 2015-11-27
          • 2020-03-13
          • 2010-12-29
          相关资源
          最近更新 更多