对于int循环的foreach循环——为什么在删除元素时foreach会引发异常?

14 浏览
0 Comments

对于int循环的foreach循环——为什么在删除元素时foreach会引发异常?

这个问题在此处已有答案:

在Java中使用foreach循环调用remove [复制]

我想知道为什么我不能在使用foreach循环迭代列表时删除元素,例如:

List objects = new ArrayList();
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循环不关心这个呢?在这个循环中,我可以轻松地删除仍在循环中的对象。谢谢

admin 更改状态以发布 2023年5月21日
0
0 Comments

就Java而言,答案在javadoc文档中(强调是自己加的):

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

0
0 Comments

最初这个问题被标签为C#,现在已经删除了。但是……

如果在集合中向前移除元素,那么for/loop并不关心这一点是不正确的。 如果你同时移除元素,那么你将无法正确地索引删除后的下一个元素,因为索引不再与下一个元素匹配。你只有在从最后一个元素到第一个元素的顺序循环时,才能避免使用for/loop时遇到问题。

foreach也存在同样的问题。枚举器维护一个Current位置来指向元素,如果你移除当前元素,然后再前进到下一个Next位置,那么Current索引器不再指向被移除的元素后面的元素,而是指向被移除的元素后两个位置的元素。

例如:

假设有一个字符串集合,其中包含“鸟类”,“动物”和“鱼类”

  • 在foreach开始时,内部的Current值为0(指向“鸟类”)
  • 你删除“鸟类”后,“动物”位于索引0(当前Current仍指向此处)
  • 你前进到下一个元素(Current = 1,指向“鱼类”)
  • 没有异常,Next前进将退出循环。

foreach没有被设计成允许这种情况。

0