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 

ここで行うべきことは、変更後に新しい iterator オブジェクトを作成することです。

...
al.add(2, "inserted");
lir = al.iterator();
while (lir.hasNext()) 
    System.out.println(lir.next());
于 2013-08-14T09:02:19.910 に答える
3

コレクションを変更してから、同じ反復子を使用しようとしています。

  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 の値が変更されます。iterator の next() メソッドは、ConcurrentModificationException をスローする checkForComodification() メソッドを呼び出します。そして、これはいわゆるフェイルファストです。

 //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 に答える