私の知る限りでは、2つのアプローチがあります。
例えば、
List<Foo> fooListCopy = new ArrayList<Foo>(fooList);
for(Foo foo : fooListCopy){
// modify actual fooList
}
そして
Iterator<Foo> itr = fooList.iterator();
while(itr.hasNext()){
// modify actual fooList using itr.remove()
}
あるアプローチを他のアプローチよりも優先する理由はありますか(たとえば、読みやすさの単純な理由から最初のアプローチを優先する)。
ConcurrentModificationException
name__を回避するためのいくつかの選択肢をいくつか例に挙げましょう。
次のような本があるとします。
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")));
収集して削除
第1の技術は、(例えば、強化された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
name__メソッドを発行することをお勧めします。
ListIteratorを使用
あなたがリストを使って作業しているならば、もう一つのテクニックは反復それ自身の間にアイテムの削除と追加をサポートするListIterator
name__を使うことにあります。
ListIterator<Book> iter = books.listIterator();
while(iter.hasNext()){
if(iter.next().getIsbn().equals(isbn)){
iter.remove();
}
}
繰り返しますが、上記の例では "remove"メソッドを使用しましたが、これはあなたの質問が暗示しているように思われるものですが、繰り返しの間に新しい要素を追加するためにadd
name__メソッドを使用することもできます。
JDK> = 8を使用
Java 8またはそれ以降のバージョンを扱う人のために、あなたがそれを利用するために使うことができる他のいくつかのテクニックがあります。
removeIf
name__基本クラスで新しいCollection
name__メソッドを使用できます。
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
name__に割り当てます(つまりbooks.removeAll(filtered)
)。
サブリストまたはサブセットを使用
他の選択肢もあります。リストがソートされていて、連続した要素を削除したい場合は、サブリストを作成してそれをクリアすることができます。
books.subList(0,5).clear();
サブリストは元のリストに基づいているので、これは要素のこのサブコレクションを削除するための効率的な方法になります。
NavigableSet.subSet
メソッド、またはそこで提供されているスライス方法のいずれかを使用したソートセットでも、同様のことが実現できます。
考慮事項
どの方法を使用するかは、あなたが何をしようとしているかによって異なります。
removeAl
name__のテクニックはどのCollection(Collection、List、Setなど)でも動作します。ListIterator
name__実装が追加および削除操作のサポートを提供するのであれば、ListIterator
name__技法は明らかにリストに対してのみ機能します。Iterator
name__アプローチは、あらゆるタイプのコレクションで機能しますが、削除操作のみをサポートします。ListIterator
name __/Iterator
name__アプローチでは、繰り返して削除するので何もコピーする必要がないという明らかな利点があります。だから、これは非常に効率的です。removeAll
name__のアプローチでの不利な点は、2回繰り返す必要があることです。まず、foor-loopで、削除基準に一致するオブジェクトを探し、それが見つかったら、元のコレクションから削除するように依頼します。それを除く。Iterator
name__インターフェースのremoveメソッドはJavadocでは "optional"としてマークされていることを言及する価値があると思います。つまり、removeメソッドを呼び出すとIterator
name__をスローするUnsupportedOperationException
name__実装が存在する可能性があります。そのため、要素の削除に対するイテレータのサポートを保証できない場合、この方法は他の方法よりも安全性が低くなります。あるアプローチを他のアプローチよりも優先する理由はありますか
最初の方法はうまくいきますが、リストをコピーすることによる明らかなオーバーヘッドがあります。
多くのコンテナは反復中に変更を許可しないため、2番目のアプローチは機能しません。 これにはArrayList
が含まれます 。
唯一の変更が現在の要素を削除することである場合、 itr.remove()
を使用して2番目のアプローチを機能させることができます(つまり、イテレータのremove()
を使用します)。 コンテナのメソッドではありません。 これはremove()
をサポートするイテレータのための私の好ましい方法です。
Java 8では、別のアプローチがあります。 コレクション#removeIf
例えば:
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.removeIf(i -> i > 2);
2番目のアプローチだけがうまくいくでしょう。 iterator.remove()
のみを使用して、反復中にコレクションを変更できます。他のすべての試みはConcurrentModificationException
を引き起こします。
remove()
メソッドを Iterator 、 あなたはExceptionがスローされるでしょう で使ったとしても、2番目のことはできません。
個人的には、すべてのCollection
name__インスタンスを最初に作成したほうがよいでしょう。新しいCollection
name__を作成するのにはまだ余計な時間がかかりますが、他の開発者による編集中にエラーが発生しにくいと思います。一部のCollection実装では、イテレータremove()
がサポートされていますが、それ以外はサポートされていません。 イテレータ のドキュメントでもっと読むことができます。
3番目の方法は、新しいCollection
name__を作成し、元のものを反復処理して、最初のCollection
name__のすべてのメンバーを2番目のCollection
name__に追加することですnot削除します。 Collection
name__のサイズと削除の数によっては、最初の方法と比較すると、これによってメモリを大幅に節約できます。
あなたがメモリのコピーをする必要がなくて、そしてイテレータがより速く働くので、私は2番目を選びます。だからあなたはメモリと時間を節約できます。
Collection
を「繰り返し」て各項目を削除する簡単な方法もあります。
List<String> list = new ArrayList<>();
//Fill the list
それは単にリストが空になるまでループすることで単純化され、そしてそれぞれの繰り返しで、remove(0)
で最初の要素を削除します。
while(!list.isEmpty()){
String s = list.remove(0);
// do you thing
}
私はこれがIterator
と比較して改善があるとは思わない、それはまだ可変リストを持っている必要がありますが、私はこの解決法の単純さが好きです。