在 ArrayList 的 foreach 循环中添加时出现 ConcurrentModificationException [英] ConcurrentModificationException when adding inside a foreach loop in ArrayList

查看:33
本文介绍了在 ArrayList 的 foreach 循环中添加时出现 ConcurrentModificationException的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将 foreach 循环与 arraylist 一起使用,但是当我使用它时,它给了我错误,但是当我使用普通的 for 循环时,它运行良好,可能是什么问题?

I'm trying to make use of the foreach loop with the arraylist, but when I use it, it gives me error, but when I use normal for loop, it works perfectly, what could be the problem?

代码在这里:

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.
}

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

this is the loop that doesnt work, and here is the one that works:

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 循环时遇到的错误是:

the error I'm getting when using the foreach loop is:

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 Collection 类是快速失败的,这意味着如果当某个线程遍历它时,集合将被更改使用迭代器,iterator.next() 将抛出一个 ConcurrentModificationException.

这种情况可能发生在多线程和单线程的情况下线程环境.- www.javacodegeeks.com

This situation can come in case of multithreaded as well as single threaded environment. - www.javacodegeeks.com

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

You can't modify a List in a for/each loop, which is syntactic sugar around the Iterator as an implementation detail. You can only safely call .remove() when using the Iterator directly.

注意 Iterator.remove 是修改集合的唯一安全方式在迭代过程中;如果底层的行为是未指定的在迭代过程中以任何其他方式修改集合进步.- Java 集合教程

Note that Iterator.remove is the only safe way to modify a collection during iteration; the behavior is unspecified if the underlying collection is modified in any other way while the iteration is in progress. - Java Collections Tutorial

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

Calling .add() inside the for/each loop modifies the contents, and the Iterator that is used behind the scenes sees this and throws this exception.

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

A more subtle concern is the that the second way you list, the .size() is increasing every time you .add() so you will end up processing all the things you .add(), this could possibly cause an endless loop depending on what the input data is. I am not sure if this is what you desire.

解决方案

我会创建另一个 ArrayList.add() 给它所有的新东西,然后在循环之后,使用 .addAll()code> 在原始 ArrayList 上将两个列表组合在一起.这将使您尝试做的事情变得明确,除非您的意图是在添加所有新添加的内容时对其进行处理.

I would create another ArrayList and .add() to it all the new things, and then after the loop, use .addAll() on the original ArrayList to combine the two lists together. This will make things explicit in what you are trying to do, that is unless your intention is process all the newly added things as you add them.

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

Always use Immutable collections classes and build new Immutable collection classes instead of trying to modify a single shared one. This is basically what my 2012 answer says but I wanted to make it more explicit.

Guava 很好地支持了这一点,使用 ImmutableList.copyOf() 来传递数据.

Guava supports this very well, use ImmutableList.copyOf() to pass around data.

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

Use Iterables.filter() to filter out stuff into a new ImmutableList, no shared mutable state, means no concurrency problems!

这篇关于在 ArrayList 的 foreach 循环中添加时出现 ConcurrentModificationException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆