Foreach反对for(int ...)循环 - 为什么foreach在删除元素时会引发异常?

时间:2013-05-27 23:03:57

标签: java for-loop foreach

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

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-loop不允许删除在循环队列中“仍然”的对象。我是对的吗?

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

由于

4 个答案:

答案 0 :(得分:3)

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

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

foreach在内部遇到同样的问题。枚举器为元素保留Current位置,如果删除元素然后前进到Next位置,Current索引器在删除元素后不会指向该元素,但是在移除一个元素后的两个位置。

例如:

假设一个字符串集合“鸟”,“动物”和“鱼”

  • 在foreach开始时,内部电流为0(指向“鸟”)
  • 你删除“鸟”,所以“动物”在索引0(当前仍然指向)
  • 您前进到下一个元素(当前= 1,指向“鱼”)
  • 没有例外,Next advance将退出循环。

foreach并未设计为允许此方案。

答案 1 :(得分:2)

就Java而言,答案在javadoc(强调我的):

  

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

答案 2 :(得分:1)

请参阅Calling remove in foreach loop in Java,一般情况下使用Iterator,如果有更多元素,请使用hasNext进行检查

答案 3 :(得分:1)

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

的Java API javadoc
  

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

另一种方法是使用允许这种修改的迭代器,而不是ArrayList的默认值或显式创建迭代器,而不是使用foreach循环,并使用它在迭代列表时改变内容的方法