1. 概要

この短いチュートリアルでは、 Java でコレクションをフィルタリングするさまざまな方法、つまり、特定の条件を満たすすべてのアイテムを見つける方法について説明します。

これは、事実上すべてのJavaアプリケーションに存在する基本的なタスクです。

このため、この目的のための機能を提供するライブラリの数は重要です。

特に、このチュートリアルでは以下について説明します。

  • Java8ストリームのfilter()関数
  • Java9フィルタリングコレクター
  • 関連するEclipseコレクションAPI
  • ApacheのCollectionUtilsfilter()メソッド
  • GuavaのCollections2filter()アプローチ

2. ストリームの使用

Java 8が導入されて以来、 Streams は、データのコレクションを処理する必要があるほとんどの場合に重要な役割を果たしてきました。

したがって、これはJavaで構築されており、追加の依存関係を必要としないため、ほとんどの場合に推奨されるアプローチです。

2.1. Streamsを使用したコレクションのフィルタリング

簡単にするために、すべての例では、整数値のコレクションから偶数のみを取得するメソッドを作成することを目的としています。

したがって、各アイテムを評価するために使用する条件を「 value%2 ==0」として表すことができます。

いずれの場合も、この条件をPredicateオブジェクトとして定義する必要があります。

public Collection<Integer> findEvenNumbers(Collection<Integer> baseCollection) {
    Predicate<Integer> streamsPredicate = item -> item % 2 == 0;

    return baseCollection.stream()
      .filter(streamsPredicate)
      .collect(Collectors.toList());
}

このチュートリアルで分析する各ライブラリは独自の述語実装を提供しますが、それでもすべてが機能インターフェイスとして定義されているため、Lambda関数を使用して宣言できることに注意してください。

この場合、要素をリストに蓄積するJavaによって提供される事前定義されたコレクターを使用しましたが、前ので説明したように、他のものを使用することもできます。 post

2.2. Java9でコレクションをグループ化した後のフィルタリング

ストリームを使用すると、 groupingByCollectorを使用してアイテムを集約できます。

ただし、前のセクションで行ったようにフィルタリングすると、このコレクターが機能する前の早い段階で一部の要素が破棄される可能性があります。

このため、フィルタリングコレクターは、サブコレクションがグループ化された後に処理することを目的として、Java9で導入されました。

この例に従って、奇数を除外する前に、各整数の桁数に基づいてコレクションをグループ化するとします。

public Map<Integer, List<Integer>> findEvenNumbersAfterGrouping(
  Collection<Integer> baseCollection) {
 
    Function<Integer, Integer> getQuantityOfDigits = item -> (int) Math.log10(item) + 1;
    
    return baseCollection.stream()
      .collect(groupingBy(
        getQuantityOfDigits,
        filtering(item -> item % 2 == 0, toList())));
}

つまり、このコレクターを使用すると、値のエントリが空になる可能性がありますが、グループ化する前にフィルタリングすると、コレクターはそのようなエントリをまったく作成しません。

もちろん、要件に基づいてアプローチを選択します。

3. Eclipseコレクションの使用

アプリケーションがJava8をサポートしていないため、またはJavaで提供されていない強力な機能を利用したい場合は、他のサードパーティライブラリを利用して目的を達成することもできます。

これは、 Eclipseコレクションの場合です。これは、新しいパラダイムに対応し、最新のすべてのJavaリリースによって導入された変更を進化させて受け入れるように努めるライブラリです。

Eclipse Collections Introductory post を調べて、このライブラリーが提供する機能についてより幅広い知識を得ることができます。

3.1. 依存関係

プロジェクトのpom.xmlに次の依存関係を追加することから始めましょう。

<dependency>
    <groupId>org.eclipse.collections</groupId>
    <artifactId>eclipse-collections</artifactId>
    <version>9.2.0</version>
</dependency>

eclipse-collections には、必要なすべてのデータ構造インターフェースとAPI自体が含まれています。

3.2. Eclipseコレクションを使用したコレクションのフィルタリング

次に、MutableListなどのデータ構造の1つでEclipseのフィルタリング機能を使用してみましょう。

public Collection<Integer> findEvenNumbers(Collection<Integer> baseCollection) {
    Predicate<Integer> eclipsePredicate
      = item -> item % 2 == 0;
 
    Collection<Integer> filteredList = Lists.mutable
      .ofAll(baseCollection)
      .select(eclipsePredicate);

    return filteredList;
}

別の方法として、 Iterateselect() staticメソッドを使用して、filteredListオブジェクトを定義することもできます。

Collection<Integer> filteredList
 = Iterate.select(baseCollection, eclipsePredicate);

4. ApacheのCollectionUtilsを使用する

ApacheのCollectionUtilsライブラリの使用を開始するには、その使用法について説明したこの短いチュートリアルを確認してください。

ただし、このチュートリアルでは、その filter()の実装に焦点を当てます。

4.1. 依存関係

まず、pom.xmlファイルに次の依存関係が必要です。

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-collections4</artifactId>
    <version>4.2</version>
</dependency>

4.2. CollectionUtilsを使用したコレクションのフィルタリング

これで、CollectonUtilsのメソッドを使用する準備が整いました。

public Collection<Integer> findEvenNumbers(Collection<Integer> baseCollection) {
    Predicate<Integer> apachePredicate = item -> item % 2 == 0;

    CollectionUtils.filter(baseCollection, apachePredicate);
    return baseCollection;
}

このメソッドは、条件に一致しないすべてのアイテムを削除することにより、baseCollectionを変更することを考慮に入れる必要があります。

これは、ベースコレクションが可変である必要があることを意味します。そうでない場合、例外がスローされます。

5. GuavaのCollections2を使用する

以前と同様に、このテーマの詳細については、以前の投稿「グアバでのコレクションのフィルタリングと変換」を読むことができます。

5.1. 依存関係

この依存関係pom.xmlファイルに追加することから始めましょう。

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>31.0.1-jre</version>
</dependency>

5.2. Collections2を使用したコレクションのフィルタリング

ご覧のとおり、このアプローチは前のセクションで行ったアプローチとかなり似ています。

public Collection<Integer> findEvenNumbers(Collection<Integer> baseCollection) {
    Predicate<Integer> guavaPredicate = item -> item % 2 == 0;
        
    return Collections2.filter(baseCollection, guavaPredicate);
}

ここでも、Guava固有のPredicateオブジェクトを定義します。

この場合、Guavaは baseCollection を変更せず、新しいコレクションを生成するため、不変のコレクションを入力として使用できます。

6. 結論

要約すると、Javaでコレクションをフィルタリングする方法はたくさんあります。

通常、Streamsが推奨されるアプローチですが、他のライブラリが提供する機能を理解し、覚えておくとよいでしょう。

特に、古いバージョンのJavaをサポートする必要がある場合。 ただし、この場合、ラムダなど、チュートリアル全体で使用されている最近のJava機能を無名クラスに置き換える必要があることに注意する必要があります。

いつものように、このチュートリアルに示されているすべての例は、Githubリポジトリにあります。