10

我在这个例外上受苦。我的代码有什么问题?我只想将 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;
    }



}

这是堆栈跟踪

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)
4

3 回答 3

19

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

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

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

于 2012-10-30T06:24:37.657 回答
7

原因?

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

这个类的迭代器和listIterator方法返回的迭代器是fail-fast:如果在迭代器创建后的任何时候列表在结构上被修改,除了通过迭代器自己的 remove 或 add 方法之外,迭代器将抛出一个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. For-Each 循环
  2. 数组列表 Java 文档
于 2012-10-30T06:30:35.173 回答
0

会计。到Java 文档

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

您在Person使用增强型 For 循环迭代对象时很想添加对象。

您可以进行以下修改:

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

if( ! duplicateFound)
{
    ps.add(p1);
}
于 2012-10-30T06:29:24.307 回答