13

イテレータを使用して CopyOnWriteArrayList から要素を削除しようとすると、例外が発生します。文書化されていることに気づきました

イテレータ自体に対する要素変更操作 (削除、設定、および追加) はサポートされていません。これらのメソッドは UnsupportedOperationException をスローします。

( http://download.oracle.com/javase/6/docs/api/java/util/concurrent/CopyOnWriteArrayList.htmlから)

さて、驚くべきことに、foreach で反復して remove() 関数を使用できます。しかし、その後、有名なバグが発生します。for ループを使用してリストから項目を削除しようとすると、削除された要素の次の要素がスキップされます。提案はありますか?

4

9 に答える 9

22

コレクションを反復処理して、削除するすべての要素を選択し、それらを一時コレクションに入れます。反復が終了したら、removeAll メソッドを使用して、見つかったすべての要素を元のコレクションから削除します。

それはあなたにとってうまくいくでしょうか?つまり、削除ロジックがアルゴリズムよりも複雑かどうかはわかりません。

于 2011-04-10T14:45:07.750 に答える
7

編集:私はばかです。これがコピー オン ライト リストであるため、すべての削除が新しいコピーを意味するという事実を見逃していました。したがって、複数の削除がある場合、以下の私の提案は最適ではない可能性があります.

イテレータが削除をサポートしていない他のリスト、またはイテレータを使用していないものと同じです。このバグを回避するために頭に浮かぶ 3 つの基本的なテクニックがあります。

  1. 何かを削除した後、インデックスをデクリメントします (次の反復までインデックスを使用して何もしないように注意してください)。このfor(int i=0; i <ためには、インデックスを操作できるように、明らかに ... スタイルの for ループを使用する必要があります。

  2. 文字通りループの先頭に戻ることなく、ループの内部で行われていることをどういうわけか繰り返します。ちょっとしたハック - 私はこのテクニックを避けます。

  3. 逆にリストを反復します (最初から最後ではなく、最後から最初に)。私はこのアプローチが最も単純であるため、このアプローチを好みます。

于 2011-04-10T14:44:57.187 に答える
5

これは であるため、CopyOnWriteArrayListで反復しながら要素を削除しても完全に安全forEachです。派手なアルゴリズムは必要ありません。

list.forEach(e -> {
    if (shouldRemove(e))
        list.remove(e);
});

編集:もちろん、位置ではなく参照によって要素を削除する場合は機能します。

于 2016-11-24T09:37:15.053 に答える
2

通常、最初に収集した要素を個別のリストで削除することを反復し、次に for each ループの外で削除します (これはとにかく、偽装された反復子ベースのループです)。

于 2011-04-10T14:46:13.397 に答える
1

このようなもの:

int pos = 0;
while(pos < lst.size() ) {
  Foo foo = lst.get(pos);
  if( hasToBeRemoved(foo) ) {
    lst.remove(pos);
    // do not move position
  } else {
    pos++;
  }
}
于 2011-04-10T14:48:59.287 に答える
1

すべてを削除したい場合は、clear() を使用してください。要素を保持したい場合は、それらを一時的な ArrayList に入れて、そこから取得します。

List<Object> tKeepThese= new ArrayList<>();
for(ListIterator<Object> tIter = theCopyOnWriteArrayList; tIter.hasNext();)
{
    tObject = tIter.next();
    if(condition to keep element)
        tKeepThese.add(tObject);
}
theCopyOnWriteArrayList.clear();
theCopyOnWriteArrayList.addAll(tKeepThese);
于 2020-02-20T08:01:36.490 に答える
0

以下は CopyOnWriteArrayList で正常に動作します

for(String key : list) {
    if (<some condition>) {
        list.remove(key);
    }
}
于 2019-01-04T11:47:30.230 に答える