を回避するためのいくつかの代替案を含むいくつかの例を挙げましょうConcurrentModificationException
。
次の本のコレクションがあるとします。
List<Book> books = new ArrayList<Book>();
books.add(new Book(new ISBN("0-201-63361-2")));
books.add(new Book(new ISBN("0-201-63361-3")));
books.add(new Book(new ISBN("0-201-63361-4")));
収集して削除
最初の手法は、削除するすべてのオブジェクトを収集することで構成され(たとえば、拡張forループを使用)、反復が終了した後、見つかったすべてのオブジェクトを削除します。
ISBN isbn = new ISBN("0-201-63361-2");
List<Book> found = new ArrayList<Book>();
for(Book book : books){
if(book.getIsbn().equals(isbn)){
found.add(book);
}
}
books.removeAll(found);
これは、実行したい操作が「削除」であると想定しています。
このアプローチを「追加」する場合も機能しますが、別のコレクションを繰り返し処理して、2番目のコレクションに追加する要素を決定addAll
し、最後にメソッドを発行するとします。
ListIteratorの使用
リストを操作している場合、別の手法はListIterator
、反復自体の間にアイテムの削除と追加をサポートするを使用することです。
ListIterator<Book> iter = books.listIterator();
while(iter.hasNext()){
if(iter.next().getIsbn().equals(isbn)){
iter.remove();
}
}
繰り返しになりますが、上記の例では「削除」メソッドを使用しました。これは、質問が示唆しているように見えますが、そのadd
メソッドを使用して、反復中に新しい要素を追加することもできます。
JDKの使用>=8
Java 8以降のバージョンを使用している場合は、Java8を利用するために使用できる他のテクニックがいくつかあります。
基本クラスで新しいremoveIf
メソッドを使用できます。Collection
ISBN other = new ISBN("0-201-63361-2");
books.removeIf(b -> b.getIsbn().equals(other));
または、新しいストリームAPIを使用します。
ISBN other = new ISBN("0-201-63361-2");
List<Book> filtered = books.stream()
.filter(b -> b.getIsbn().equals(other))
.collect(Collectors.toList());
この最後のケースでは、コレクションから要素をフィルター処理するには、元の参照をフィルター処理されたコレクションに再割り当てするbooks = filtered
か(つまり)、フィルター処理されたコレクションをremoveAll
元のコレクションから見つかった要素に使用します(つまりbooks.removeAll(filtered)
)。
サブセットまたはサブセットを使用する
他の選択肢もあります。リストがソートされていて、連続する要素を削除したい場合は、サブリストを作成してからクリアすることができます。
books.subList(0,5).clear();
サブリストは元のリストに基づいているため、これはこの要素のサブコレクションを削除する効率的な方法になります。
方法を使用してソートされたセットNavigableSet.subSet
、またはそこで提供されているスライス方法のいずれかを使用して、同様のことを実現できます。
考慮事項:
どの方法を使用するかは、意図していることによって異なります。
- 収集と
removeAl
手法は、任意のコレクション(コレクション、リスト、セットなど)で機能します。
ListIterator
与えられたListIterator
実装が追加および削除操作のサポートを提供する場合 、この手法は明らかにリストでのみ機能します。
- この
Iterator
アプローチはどのタイプのコレクションでも機能しますが、削除操作のみをサポートします。
ListIterator
/アプローチを使用Iterator
すると、反復しながら削除するため、何もコピーする必要がないという明らかな利点があります。したがって、これは非常に効率的です。
- JDK 8ストリームの例では、実際には何も削除されませんが、目的の要素が検索され、元のコレクション参照が新しいものに置き換えられ、古いコレクションがガベージコレクションされます。したがって、コレクションを1回だけ繰り返すと、効率的です。
- 収集と
removeAll
アプローチの欠点は、2回反復する必要があることです。最初に、削除基準に一致するオブジェクトを探してfoor-loopを繰り返し、それを見つけたら、元のコレクションから削除するように依頼します。これは、次のことを行うために、このアイテムを探すための2回目の反復作業を意味します。それを除く。
Iterator
インターフェイスのremoveメソッドは、Javadocで「オプション」としてマークされていることを言及する価値があると思います。つまり、removeメソッドを呼び出すIterator
とスローされる実装が存在する可能性があります。UnsupportedOperationException
そのため、要素の削除に対するイテレータのサポートを保証できない場合、このアプローチは他のアプローチよりも安全性が低いと言えます。