插入 ArrayList 时出现 java.util.ConcurrentModificationException

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18227245/
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-08-11 23:30:55  来源:igfitidea点击:

java.util.ConcurrentModificationException while inserting in ArrayList

javacollections

提问by user2681668

import java.util.ArrayList;
import java.util.Iterator;
import java.util.ListIterator;

public class MyList {
    public static void main(String[] args) {
        ArrayList<String> al = new ArrayList<String>();

        al.add("S1");
        al.add("S2");
        al.add("S3");
        al.add("S4");

        Iterator<String> lir = al.iterator();

        while (lir.hasNext()) {
            System.out.println(lir.next());
        }

        al.add(2, "inserted");

        while (lir.hasNext()) {
           System.out.println(lir.next());
        }
    }
}

The particular piece of code throws an error:

特定的代码段引发错误:

Exception in thread "main" java.util.ConcurrentModificationException
    at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
    at java.util.ArrayList$Itr.next(Unknown Source)
    at collections.MyList.main(MyList.java:32)

回答by Aniket Thakur

You are modifying the Collection and then trying to use the same iterator.

您正在修改集合,然后尝试使用相同的迭代器。

  1. Get the Collection iterator again

    al.add(2, "inserted");
    Iterator<String> lirNew = al.iterator();
    while (lirNew.hasNext()) {
    System.out.println(lirNew.next());
    }
    
  2. or Use ListIterator

    ArrayList<String> al = new ArrayList<String>();
    
    al.add("S1");
    al.add("S2");
    al.add("S3");
    al.add("S4");
    
    ListIterator<String> lir = al.listIterator();
    
    while (lir.hasNext()) {
        System.out.println(lir.next());
    
    }
    
    lir.add("insert");
    
    while (lir.hasNext()) {
        System.out.println(lir.next());
    
    }
    
  1. 再次获取 Collection 迭代器

    al.add(2, "inserted");
    Iterator<String> lirNew = al.iterator();
    while (lirNew.hasNext()) {
    System.out.println(lirNew.next());
    }
    
  2. 或使用ListIterator

    ArrayList<String> al = new ArrayList<String>();
    
    al.add("S1");
    al.add("S2");
    al.add("S3");
    al.add("S4");
    
    ListIterator<String> lir = al.listIterator();
    
    while (lir.hasNext()) {
        System.out.println(lir.next());
    
    }
    
    lir.add("insert");
    
    while (lir.hasNext()) {
        System.out.println(lir.next());
    
    }
    

回答by Subhrajyoti Majumder

It happens due to array list is modified after creation of Iterator.

这是由于创建Iterator.

The iterators returned by this ArrayList's iterator and listIterator methods 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.

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

Documentation

文档

Iterator<String> lir = al.iterator(); // Iterator created

while (lir.hasNext()) 
    System.out.println(lir.next());
al.add(2, "inserted"); // List is modified here
while (lir.hasNext()) 
    System.out.println(lir.next());// Again it try to access list 

What you should do here create new iterator object after modification.

你应该在这里做的是在修改后创建新的迭代器对象。

...
al.add(2, "inserted");
lir = al.iterator();
while (lir.hasNext()) 
    System.out.println(lir.next());

回答by criszhao

You add object to list, after the iterator is instanced. This will change the value of modCount in inner class AbstractList$Itr.class. next() method of iterator will call checkForComodification() method, which throws a ConcurrentModificationException. And this is so called fail-fast.

在实例化迭代器后,将对象添加到列表中。这将改变内部类 AbstractList$Itr.class 中 modCount 的值。迭代器的 next() 方法将调用 checkForComodification() 方法,该方法抛出 ConcurrentModificationException。这就是所谓的快速失败。

 //add in abstractList
 public void add(int index, E element) {
    if (index<0 || index>size)
        throw new IndexOutOfBoundsException();
    checkForComodification();
    l.add(index+offset, element);
    expectedModCount = l.modCount;
    size++;
    modCount++;  //modCount changed
}

In AbstractList$Itr

在 AbstractList$Itr 中

int expectedModCount;

public E next() {
        checkForComodification(); // cause ConcurrentModificationException
    try {
    E next = get(cursor);
    lastRet = cursor++;
    return next;
    } catch (IndexOutOfBoundsException e) {
    checkForComodification();
    throw new NoSuchElementException();
    }
}

 private void checkForComodification() {
    if (l.modCount != expectedModCount)  //modCount not equals to itr.expectedModCount
        throw new ConcurrentModificationException();
}

redo this code after your add:

添加后重做此代码:

al.add(2, "inserted");
lir = al.iterator();