Java 9の新しいストリームコレクタ

Java 9の新しいストリームコレクター

1. 概要

CollectorsはJava 8で追加され、入力要素をMapListSetなどの可変コンテナーに蓄積するのに役立ちました。

この記事では、要素のインテリジェントなコレクションを提供するCollectors.groupingByと組み合わせて使用​​されるtwo new collectors added in Java 9: Collectors.filtering andCollectors.flatMappingについて説明します。

2. Filtering Collector

Collectors.filteringStream filter()に似ています。 filtering入力要素に使用されますが、さまざまなシナリオに使用されます。 Stream’sfilterはストリームチェーンで使用されますが、filteringgroupingByと一緒に使用するように設計されたCollectorです。

Stream’sfilterを使用すると、値が最初にフィルタリングされ、次にグループ化されます。 このようにして、除外された値はなくなり、その痕跡はありません。 トレースが必要な場合は、最初にグループ化してから、実際にCollectors.filteringが行うフィルタリングを適用する必要があります。

Collectors.filteringは、入力要素をフィルタリングする関数と、フィルタリングされた要素を収集するコレクターを取ります。

@Test
public void givenList_whenSatifyPredicate_thenMapValueWithOccurences() {
    List numbers = List.of(1, 2, 3, 5, 5);

    Map 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 Collector

Collectors.flatMappingCollectors.mappingに似ていますが、よりきめ細かい目的があります。 両方のコレクターは、要素が収集される関数とコレクターを取りますが、flatMapping関数は、コレクターによって累積される要素のStreamを受け入れます。

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

class Blog {
    private String authorName;
    private List 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 blogs = List.of(blog1, blog2);

    Map>> 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> 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() and Collectors.flatMapping() used in combination with Collectors.groupingBy()

これらのコレクターはCollectors.partitioningBy()と一緒に使用することもできますが、条件に基づいて2つのパーティションを作成するだけであり、コレクターの実際の能力は活用されません。したがって、このチュートリアルから除外しました。

このチュートリアルのコードスニペットの完全なソースコードは、over on GitHubで入手できます。