387

ArrayList次のように繰り返しながら、からいくつかの要素を削除しようとしています:

for (String str : myArrayList) {
    if (someCondition) {
        myArrayList.remove(str);
    }
}

もちろん、ConcurrentModificationException反復時にリストから項目を同時に削除しようとすると、 が発生しますmyArrayList。この問題を解決する簡単な解決策はありますか?

4

10 に答える 10

619

を使用しIteratorて呼び出しますremove():

Iterator<String> iter = myArrayList.iterator();

while (iter.hasNext()) {
    String str = iter.next();

    if (someCondition)
        iter.remove();
}
于 2013-08-26T16:29:00.610 に答える
215

他のみんなの答えに代わるものとして、私はいつも次のようなことをしてきました:

List<String> toRemove = new ArrayList<String>();
for (String str : myArrayList) {
    if (someCondition) {
        toRemove.add(str);
    }
}
myArrayList.removeAll(toRemove);

これにより、イテレータを直接処理する必要がなくなりますが、別のリストが必要になります。なんらかの理由で、私はいつもこのルートを好んでいました。

于 2013-08-26T16:35:07.663 に答える
70

イテレータの remove() メソッドを使用する必要があります。これは、強化された for ループがないことを意味します。

for (final Iterator iterator = myArrayList.iterator(); iterator.hasNext(); ) {
    iterator.next();
    if (someCondition) {
        iterator.remove();
    }
}
于 2013-08-26T16:29:07.257 に答える
41

ダメダメダメ!

単一の脅威のあるタスクでは、Iterator や CopyOnWriteArrayList を使用する必要はありません (パフォーマンス ヒットのため)。

解決策ははるかに簡単です: for-each loop の代わりに正規の for ループを使用してみてください

Java の著作権所有者 (数年前は Sun、現在は Oracle) によると、for-each ループ ガイドでは、イテレータを使用してコレクションをウォークスルーし、それを非表示にしてコードの見栄えを良くしています。しかし、残念なことに、収益よりも多くの問題が発生したことがわかります。そうでなければ、このトピックは発生しませんでした。

たとえば、次のコードは、変更された ArrayList で次の反復に入るとき、java.util.ConcurrentModificationException につながります。

        // process collection
        for (SomeClass currElement: testList) {

            SomeClass founDuplicate = findDuplicates(currElement);
            if (founDuplicate != null) {
                uniqueTestList.add(founDuplicate);
                testList.remove(testList.indexOf(currElement));
            }
        }

しかし、次のコードは問題なく動作します。

    // process collection
    for (int i = 0; i < testList.size(); i++) {
        SomeClass currElement = testList.get(i);

        SomeClass founDuplicate = findDuplicates(currElement);
        if (founDuplicate != null) {
            uniqueTestList.add(founDuplicate);
            testList.remove(testList.indexOf(currElement));
            i--; //to avoid skipping of shifted element
        }
    }

したがって、コレクションを反復処理するためにインデックス作成アプローチを使用し、for-each ループを避けるようにしてください。これらは同等ではないためです! For-each ループは、コレクションの変更をチェックし、ConcurrentModificationException 例外をスローするいくつかの内部反復子を使用します。これを確認するには、私が投稿した最初の例を使用するときに、出力されたスタック トレースを詳しく見てください。

Exception in thread "main" java.util.ConcurrentModificationException
    at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)
    at java.util.AbstractList$Itr.next(AbstractList.java:343)
    at TestFail.main(TestFail.java:43)

マルチスレッドの場合、対応するマルチタスク アプローチを使用します (synchronized キーワードなど)。

于 2014-11-14T14:41:16.383 に答える
8

トラバーサル中にリストを変更したい場合は、Iterator. そして、iterator.remove()トラバーサル中に要素を削除するために使用できます。

于 2013-08-26T16:28:25.053 に答える
7
List myArrayList  = Collections.synchronizedList(new ArrayList());

//add your elements  
 myArrayList.add();
 myArrayList.add();
 myArrayList.add();

synchronized(myArrayList) {
    Iterator i = myArrayList.iterator(); 
     while (i.hasNext()){
         Object  object = i.next();
     }
 }
于 2013-08-26T16:48:55.957 に答える
2

反復子 remove() 関数を使用して、基になるコレクション オブジェクトからオブジェクトを削除できます。ただし、この場合、同じオブジェクトをリストから削除できますが、他のオブジェクトは削除できません。

ここから

于 2014-04-16T13:23:21.140 に答える