在ArrayList中添加foreach循环时,ConcurrentModificationException

hak*_*ata 19 java foreach for-loop arraylist

我正在尝试使用arraylist的foreach循环,但是当我使用它时,它会给我错误,但是当我使用普通for循环时,它完美地工作,可能是什么问题?

代码在这里:

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.
}
Run Code Online (Sandbox Code Playgroud)

这是不起作用的循环,这是一个有效的循环:

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.
}
Run Code Online (Sandbox Code Playgroud)

我在使用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)
Run Code Online (Sandbox Code Playgroud)

小智 35

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

在多线程以及单线程环境的情况下可能出现这种情况.- www.javacodegeeks.com

你不能修改List一个for/each循环,这是周围的语法糖Iterator作为一个实现细节.您只能.remove()Iterator直接使用时安全地拨打电话.

请注意,Iterator.remove是在迭代期间修改集合的唯一安全方法; 如果在迭代进行过程中以任何其他方式修改基础集合,则行为未指定.- Java Collections教程

.add()for/each循环内部调用会修改内容,而Iterator在幕后使用的内容会看到此内容并抛出此异常.

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

我会创建另一个ArrayList.add()所有新的东西,然后在循环之后,使用.addAll()原始ArrayList来将两个列表组合在一起.这将使你想要做的事情明确,除非你的意图是在你添加它们时处理所有新添加的东西.

2014解决方案:

始终使用Immutable集合类并构建新的Immutable集合类,而不是尝试修改单个共享类.这基本上是我2012年的回答,但我想让它更明确.

Guava非常支持这一点,用于ImmutableList.copyOf()传递数据.

用于Iterables.filter()将东西过滤成新的ImmutableList,没有共享的可变状态,意味着没有并发问题!

  • 您的陈述是错误的,"您不能修改for/each循环中的List".您可以修改foreach循环中的列表.唯一的警告是你必须在修改列表后突破循环. (3认同)