1. 概要

このクイックチュートリアルでは、特定の述語に一致するJavaコレクションからアイテムを削除する4つの異なる方法について説明します。

当然、いくつかの注意点も見ていきます。

2. コレクションの定義

最初に、元のデータ構造を変更する2つのアプローチを説明します。 次に、アイテムを削除する代わりに、アイテムなしで元のコレクションのコピーを作成する他の2つのオプションについて説明します。

例全体で次のコレクションを使用して、さまざまな方法を使用して同じ結果を達成する方法を示しましょう。

Collection<String> names = new ArrayList<>();
names.add("John");
names.add("Ana");
names.add("Mary");
names.add("Anthony");
names.add("Mark");

3. イテレータを使用した要素の削除

JavaのIteratorを使用すると、Collection内のすべての個々の要素をウォークおよび削除できます。

そのためには、最初に iterator メソッドを使用して、その要素に対してイテレーターを取得する必要があります。 その後、 next を使用して各要素にアクセスし、removeを使用してそれらを削除できます。

Iterator<String> i = names.iterator();

while(i.hasNext()) {
    String e = i.next();
    if (e.startsWith("A")) {
        i.remove();
    }
}

その単純さにもかかわらず、考慮すべきいくつかの注意事項があります。

  • コレクションによっては、ConcurrentModificationException例外が発生する場合があります
  • 要素を削除する前に、要素を反復処理する必要があります
  • コレクションによっては、removeの動作が予想と異なる場合があります。 例えば: ArrayList.Iterator コレクションから要素を削除し、後続のデータを左にシフトしますが、 LinkedList.Iterator 次の要素へのポインタを調整するだけです。 そのため、アイテムを削除する場合、LinkedList.IteratorArrayList.Iteratorよりもはるかに優れたパフォーマンスを発揮します

4. Java8およびCollection.removeIf()

Java 8は、コレクションインターフェイスに新しいメソッドを導入しました。これは、述語 を使用して要素を削除するためのより簡潔な方法を提供します。

names.removeIf(e -> e.startsWith("A"));

Iterator アプローチとは異なり、removeIfLinkedListArrayListの両方で同様に機能することに注意してください。

Java 8では、 ArrayList は、 Iterator に依存するデフォルトの実装をオーバーライドし、別の戦略を実装します。最初に、要素を反復処理し、に一致する要素にマークを付けます。述語;その後、2回目の反復を繰り返して、最初の反復でマークされた要素を削除(およびシフト)します。

5. Java8とStreamの紹介

Java 8の新しい主要機能の1つは、 Stream (および Collectors )の追加でした。 ソースからStreamを作成する方法はたくさんあります。 ただし、 Stream インスタンスに影響を与えるほとんどの操作は、そのソースを変更しません。むしろ、APIは、ソースのコピーを作成し、それらで必要になる可能性のある操作を実行することに重点を置いています。

StreamおよびCollectorsを使用して、述語と一致する要素と一致しない要素を検索/フィルタリングする方法を見てみましょう。

5.1. Streamを使用した要素の削除

ストリームを使用したフィルタリング要素の削除は非常に簡単ですコレクションを使用してStreamのインスタンスを作成し、filter[を呼び出す必要があります。 X190X]とPredicateを使用し、 collect を使用して、 Collectors:を使用して結果を収集します。

Collection<String> filteredCollection = names
  .stream()
  .filter(e -> !e.startsWith("A"))
  .collect(Collectors.toList());

ストリーミングは、以前のアプローチよりも侵襲性が低く、分離を促進し、同じソースから複数のコピーを作成できるようにします。 ただし、アプリケーションで使用されるメモリも増加することに注意してください。

5.2. Collectors.partitioningBy

Stream.filterCollectorsの両方を組み合わせると非常に便利ですが、一致する要素と一致しない要素の両方が必要なシナリオに遭遇する可能性があります。このような場合、 Collectors.partitioningBy を利用できます:

Map<Boolean, List<String>> classifiedElements = names
    .stream()
    .collect(Collectors.partitioningBy((String e) -> 
      !e.startsWith("A")));

String matching = String.join(",",
  classifiedElements.get(true));
String nonMatching = String.join(",",
  classifiedElements.get(false));

このメソッドは、truefalseの2つのキーのみを含むMapを返します。各キーは、一致する要素と一致しない要素をそれぞれ含むリストを指します。 。

6. 結論

この記事では、コレクションから要素を削除するためのいくつかの方法と、それらの警告のいくつかについて説明しました。

この記事の完全なソースコードとすべてのコードスニペットは、GitHubにあります。