在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()。
在第一种情况下,你有一个迭代器打开数组列表。 当你做一个添加,然后再次迭代迭代器注意到你下面的数据结构已经改变。
在看的情况下,你只是每次都得到一个新的元素,并没有并发修改问题,虽然随着添加更多的元素,大小也在变化。
要解决您可能想要添加到临时位置的问题,并在循环之后添加或者复制初始数据并添加到原始位置。