插入ArrayList时出现java.util.ConcurrentModificationException

时间:2013-08-14 08:56:16

标签: java collections

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

特定的代码会引发错误:

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)

3 个答案:

答案 0 :(得分:6)

由于数组列表在创建Iterator后被修改,因此发生了这种情况。

  

此ArrayList的迭代器和listIterator返回的迭代器   方法是快速失败的:如果列表在结构上被修改了   创建迭代器之后的时间,除了通过之外的任何方式   迭代器自己删除或添加方法,迭代器会抛出一个   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 

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

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

答案 1 :(得分:3)

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

  1. 再次获取Collection iterator

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

答案 2 :(得分:0)

在实例化迭代器之后,将对象添加到列表中。这将更改内部类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
}

在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();
}

在添加后重做此代码:

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