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

3 回答 3

7

这是由于数组列表在创建后被修改而发生的Iterator

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

文档

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());
于 2013-08-14T09:02:19.910 回答
3

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

  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());
    
    }
    
于 2013-08-14T09:01:54.770 回答
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();
于 2013-08-14T09:09:22.453 回答