添加另一个对象时出现 java.util.ConcurrentModificationException

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13133688/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 11:37:11  来源:igfitidea点击:

java.util.ConcurrentModificationException when adding another object

java

提问by Rohit Jain

I'm suffering on this exception. What's the problem on my code? I just want to separate Person's duplicate name in another ArrayList

我正在为这个例外感到痛苦。我的代码有什么问题?我只想将 Person 的重复名称分开ArrayList

public class GlennTestMain
{

    static ArrayList<Person> ps;

    static ArrayList<Person> duplicates;
    public static void main(String[] args)
    {
        ps = new ArrayList<GlennTestMain.Person>();

        duplicates = new ArrayList<GlennTestMain.Person>();

        noDuplicate(new Person("Glenn", 123));
        noDuplicate(new Person("Glenn", 423));
        noDuplicate(new Person("Joe", 1423)); // error here


        System.out.println(ps.size());
        System.out.println(duplicates.size());
    }

    public static void noDuplicate(Person p1)
    {
        if(ps.size() != 0)
        {
            for(Person p : ps)
            {
                if(p.name.equals(p1.name))
                {
                    duplicates.add(p1);
                }
                else
                {
                    ps.add(p1);
                }
            }
        }
        else
        {
            ps.add(p1);
        }
    }

    static class Person
    {
        public Person(String n, int num)
        {
            this.name = n;
            this.age = num;
        }
        String name;
        int age;
    }



}

Here's the stacktrace

这是堆栈跟踪

Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
at java.util.ArrayList$Itr.next(Unknown Source)
at hk.com.GlennTestMain.noDuplicate(GlennTestMain.java:41)
at hk.com.GlennTestMain.main(GlennTestMain.java:30)

回答by Rohit Jain

You cannot modify the collectionyou are iterating on. That might throw a ConcurrentModificationException. Though it might work sometimes, but it is not guaranteed to work everytime.

您不能修改collection正在迭代的对象。那可能会抛出一个ConcurrentModificationException. 虽然它有时可能会起作用,但不能保证每次都起作用。

If you want to add, or remove something from your list, you need to use an Iterator, or ListIteratorfor your list. And use ListIterator#addmethod to add anything in your list. Even if in your iterator, if you try to use List.addor List.remove, you will get that exception, because that doesn't make any difference. You should use the methods of iterator.

如果您想在列表中添加或删除某些内容,则需要对列表使用Iterator, 或ListIterator。并使用ListIterator#add方法在您的列表中添加任何内容。即使在您的 中iterator,如果您尝试使用List.addList.remove,您也会遇到该异常,因为这没有任何区别。您应该使用 的方法iterator

See these posts to understand how to use it: -

请参阅这些帖子以了解如何使用它:-

回答by Amit Deshpande

Reason?

原因?

Iterators returned by ArrayListis fail-fastin nature.

迭代器返回的ArrayList的fail-fast自然界中。

The iterators returned by this class's iterator and listIteratormethods are fail-fast: if the list is structurally modified at any time after the iterator is created, in any way except through the iterator's own remove or add methods, the iterator will throw a ConcurrentModificationException. Thus, in the face of concurrent modification, the iterator fails quickly and cleanly, rather than risking arbitrary, non-deterministic behavior at an undetermined time in the future.

此类的迭代器和listIterator方法返回的迭代器是fail-fast:如果在迭代器创建后的任何时间对列表进行结构修改,除了通过迭代器自己的 remove 或 add 方法以外的任何方式,迭代器都会抛出一个ConcurrentModificationException. 因此,面对并发修改,迭代器快速而干净地失败,而不是冒着在未来不确定的时间出现任意、非确定性行为的风险。

Where does this iterator Come from while I am not using it?

当我不使用它时,这个迭代器来自哪里?

For enhanced for loop for collections Iteratorgets used so you can not call addmethod while you are iterating.

对于集合的增强 for 循环Iterator被使用,因此您不能add在迭代时调用方法。

So your loop is same as below

所以你的循环与下面相同

for (Iterator<Entry> i = c.iterator(); i.hasNext(); ){   

What is the Solution Then ?

那么解决方案是什么?

You can call iterator.add();and change loop based on iterator explicitly rather than implicitly.

您可以iterator.add();基于迭代器显式而不是隐式地调用和更改循环。

    String inputWord = "john";
    ArrayList<String> wordlist = new ArrayList<String>();
    wordlist.add("rambo");
    wordlist.add("john");
    for (ListIterator<String> iterator = wordlist.listIterator(); iterator
            .hasNext();) {
        String z = iterator.next();
        if (z.equals(inputWord)) {
            iterator.add("3");
        }
    }
    System.out.println(wordlist.size());

Now Where Can I Read more?

现在在哪里可以阅读更多信息?

  1. The For-Each Loop
  2. ArrayList Java docs
  1. For-Each 循环
  2. ArrayList Java 文档

回答by Azodious

Acc. to Java Docs:

累积 到Java 文档

if a thread modifies a collection directly while it is iterating over the collection with a fail-fast iterator, the iterator will throw this exception.

如果线程在使用快速失败迭代器迭代集合时直接修改集合,则迭代器将抛出此异常。

You are tyring to add a Personobject while iterating it using Enhanced For loop.

您在Person使用Enhanced For loop进行迭代时很想添加一个对象。

You can do following modification:

您可以进行以下修改:

boolean duplicateFound = false;
for(Person p : ps)
{
    if(p.name.equals(p1.name))
    {
        duplicates.add(p1);
        duplicateFound = true;
    }
}

if( ! duplicateFound)
{
    ps.add(p1);
}