1概要

Java 8ではhttps://docs.oracle.com/javase/8/docs/api/java/util/stream/Collectors.html[

Collectors

]が追加され、入力要素を

Map



List



セット

この記事では、Java 9で追加された2つの新しいコレクター、つまり

Collectors.filtering

および




Collectors.flatMapping ** を、

Collectors.groupingBy

と組み合わせて使用​​して、インテリジェントな要素のコレクションを提供する方法を説明します。


2

フィルターコレクター



Collectors.filtering



Stream filter()

に似ています。これはinput要素のフィルタリングに使用されていますが、さまざまなシナリオに使用されています。


Stream’


filter

はストリームチェーンで使用されますが、

filtering



groupingBy

と共に使用するように設計された

Collector

です。


Stream’s


filter

では、値が最初にフィルタ処理され、次にグループ化されます。このようにして、除外された値はなくなり、その痕跡はありません。トレースが必要な場合は、最初にグループ化してから

Collectors.filtering

が実際に行うフィルタリングを適用する必要があります。


Collectors.filtering

は、入力要素をフィルタ処理するための関数と、フィルタ処理された要素を収集するためのコレクタを取ります。

@Test
public void givenList__whenSatifyPredicate__thenMapValueWithOccurences() {
    List<Integer> numbers = List.of(1, 2, 3, 5, 5);

    Map<Integer, Long> result = numbers.stream()
      .filter(val -> val > 3)
      .collect(Collectors.groupingBy(i -> i, Collectors.counting()));

    assertEquals(1, result.size());

    result = numbers.stream()
      .collect(Collectors.groupingBy(i -> i,
        Collectors.filtering(val -> val > 3, Collectors.counting())));

    assertEquals(4, result.size());
}


3

FlatMappingコレクター



Collectors.flatMapping



Collectors.mapping

に似ていますが、よりきめ細かい目的を持っています。両方のコレクターは、要素が収集される関数とコレクターを取りますが、

flatMapping

関数は、要素の

Stream

を受け入れ、それらはその後コレクターによって累積されます。

次のモデルクラスを見てみましょう。

class Blog {
    private String authorName;
    private List<String> comments;

   //constructor and getters
}


Collectors.flatMapping

を使用すると、中間コレクションをスキップして、

Collectors.groupingBy

で定義されたそのグループにマッピングされている単一のコンテナーに直接書き込むことができます。

@Test
public void givenListOfBlogs__whenAuthorName__thenMapAuthorWithComments() {
    Blog blog1 = new Blog("1", "Nice", "Very Nice");
    Blog blog2 = new Blog("2", "Disappointing", "Ok", "Could be better");
    List<Blog> blogs = List.of(blog1, blog2);

    Map<String,  List<List<String>>> authorComments1 = blogs.stream()
     .collect(Collectors.groupingBy(Blog::getAuthorName,
       Collectors.mapping(Blog::getComments, Collectors.toList())));

    assertEquals(2, authorComments1.size());
    assertEquals(2, authorComments1.get("1").get(0).size());
    assertEquals(3, authorComments1.get("2").get(0).size());

    Map<String, List<String>> authorComments2 = blogs.stream()
      .collect(Collectors.groupingBy(Blog::getAuthorName,
        Collectors.flatMapping(blog -> blog.getComments().stream(),
        Collectors.toList())));

    assertEquals(2, authorComments2.size());
    assertEquals(2, authorComments2.get("1").size());
    assertEquals(3, authorComments2.get("2").size());
}


Collectors.mapping

は、グループ化されたすべての作者のコメントをコレクターのコンテナー(つまりList)にマップしますが、この中間コレクションは、コレクターのコンテナーにマップされるコメントリストの直接ストリームを提供するので

flatMapping

によって削除されます。


4結論

この記事では、

Java9

で導入された新しい

Collectors

、つまり


Collectors.filtering()

および

Collectors.flatMapping()



Collectors.groupingBy()


と組み合わせて使用​​する方法について説明します。

これらのコレクターは

Collectors.partitioningBy()

と一緒に使用することもできますが、条件に基づいて2つのパーティションを作成するだけで、コレクターの本当の力は活用されません。そのため、このチュートリアルは省略しました。

このチュートリアルのコードスニペットの完全なソースコードはhttps://github.com/eugenp/tutorials/tree/master/core-java-9[GitHubで利用可能]です。