在ArrayList中添加foreach循环时出现ConcurrentModificationException

我试图利用与数组列表foreach循环,但是当我使用它,它给了我错误,但是当我使用正常的循环,它完美的作品,可能是什么问题?

代码在这里:

for (Pair p2 : R) { if ((p2.getFirstElm() == p.getSecondElm()) && (p2.getFirstElm() != p2.getSecondElm())) R.add(new Pair (p.getFirstElm(), p2.getSecondElm())); else if ((p2.getSecondElm() == p.getFirstElm()) && (p2.getFirstElm() != p2.getSecondElm())) R.add(new Pair (p2.getFirstElm(), p.getSecondElm())); // else // There are no transitive pairs in R. } 

这是不工作的循环,这是工作的那个:

 for (int i = 0; i < R.size(); i++) { if ((R.get(i).getFirstElm() == p.getSecondElm()) && (R.get(i).getFirstElm() != R.get(i).getSecondElm())) R.add(new Pair (p.getFirstElm(), R.get(i).getSecondElm())); else if ((R.get(i).getSecondElm() == p.getFirstElm()) && (R.get(i).getFirstElm() != R.get(i).getSecondElm())) R.add(new Pair (R.get(i).getFirstElm(), p.getSecondElm())); //else // There are no transitive pairs in R. } 

我在使用foreach循环时遇到的错误是:

 Exception in thread "main" java.util.ConcurrentModificationException at java.util.AbstractList$Itr.checkForComodification(Unknown Source) at java.util.AbstractList$Itr.next(Unknown Source) at set.problem.fourth.PoSet.makeTransitive(PoSet.java:145) at set.problem.fourth.PoSet.addToR(PoSet.java:87) at set.problem.fourth.PoSetDriver.typicalTesting(PoSetDriver.java:35) at set.problem.fourth.PoSetDriver.main(PoSetDriver.java:13) 

Java集合类是快速失败的,这意味着如果在某个线程使用迭代器遍历它时集合将被更改,则iterator.next()将抛出ConcurrentModificationException

这种情况可能出现在multithreading以及单线程环境的情况下。 – http://www.javacodegeeks.com

你不能在for/each循环中修改一个List ,它是Iterator周围的语法糖作为实现细节。 直接使用Iterator时,只能安全地调用.remove()

请注意,Iterator.remove是在迭代期间修改集合的唯一安全方法; 如果在迭代过程中以其他方式修改了底层集合,则行为是未指定的。 – Java集合教程

for/each循环中调用.add()会修改内容,而在后台使用的Iterator会看到这个并引发这个exception。

一个更微妙的问题是,你列出的第二种方式, .add()每次增加.add()所以你最终将处理所有的事情.add() ,这可能会导致无限循环取决于关于input数据是什么 我不确定这是不是你想要的。

我将创build另一个ArrayList.add()它所有的新东西,然后在循环后,使用原始ArrayList上的.addAll()将两个列表组合在一起。 这会使事情变得明确,除非你的意图是在添加新事物的过程中处理所有的新事物。

2014解决scheme:

总是使用Immutable集合类并构build新的Immutable集合类,而不是尝试修改单个共享类。 这基本上是我2012年的答案,但我想更加明确。

番石榴支持这一点,使用ImmutableList.copyOf()传递数据。

使用Iterables.filter()过滤掉一个新的ImmutableList ,没有共享的可变状态,意味着没有并发性问题!

在引擎盖下,Java中的for-each循环使用遍历集合的Iterator (请参阅本文中的详细说明)。如果您在迭代集合的同时修改集合,则Iterator将抛出ConcurrentModificationException ,请参阅此文章 。

问题是你正在循环的第一行做R.add()。

在第一种情况下,你有一个迭代器打开数组列表。 当你做一个添加,然后再次迭代迭代器注意到你下面的数据结构已经改变。

在看的情况下,你只是每次都得到一个新的元素,并没有并发修改问题,虽然随着添加更多的元素,大小也在变化。

要解决您可能想要添加到临时位置的问题,并在循环之后添加或者复制初始数据并添加到原始位置。