【问题标题】:java.util.ConcurrentModificationException when adding another object添加另一个对象时出现 java.util.ConcurrentModificationException
【发布时间】:2012-10-30 06:20:38
【问题描述】:

我正在为这个例外而受苦。我的代码有什么问题? 我只是想在另一个ArrayList中分隔Person的重名

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



}

这是堆栈跟踪

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)

【问题讨论】:

标签: java


【解决方案1】:

您不能修改您正在迭代的collection。这可能会引发ConcurrentModificationException。虽然它有时可能会起作用,但不能保证每次都起作用。

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

查看这些帖子以了解如何使用它:-

【讨论】:

    【解决方案2】:

    原因?

    ArrayList 返回的迭代器本质上是fail-fast

    这个类的迭代器和listIterator方法返回的迭代器是fail-fast:如果列表在迭代器创建后的任何时候被结构修改,除了通过迭代器自己的删除或添加方法之外,迭代器将抛出一个ConcurrentModificationException。因此,面对并发修改,迭代器会快速而干净地失败,而不是在未来不确定的时间冒任意的、非确定性的行为。

    这个迭代器在我不使用的时候是从哪里来的?

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

    所以你的循环和下面的一样

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

    那么解决方案是什么?

    您可以调用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());
    

    现在我可以在哪里阅读更多内容?

    1. The For-Each Loop
    2. ArrayList Java docs

    【讨论】:

    • 只有在使用迭代器迭代集合的元素并修改它们时才会发生 CME?
    【解决方案3】:

    累加。致Java Docs

    如果线程在使用fail-fast迭代器迭代集合时直接修改集合,迭代器将抛出此异常。

    您在使用Enhanced For loop 迭代它的同时添加了一个Person 对象。

    您可以进行以下修改:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-12-30
      • 2021-03-15
      • 2021-08-05
      • 2018-10-02
      • 2015-05-27
      • 1970-01-01
      • 2021-07-14
      相关资源
      最近更新 更多