New Stream Collectors in Java 9 – Java 9中新的流收集器

最后修改: 2017年 1月 27日

1. Overview


Collectors were added in Java 8 which helped accumulate input elements into mutable containers such as Map, List, and Set.

Collectors在Java 8中被添加,它有助于将输入元素累积到可变的容器中,如MapListSet

In this article, we’re going to explore two new collectors added in Java 9: Collectors.filtering and Collectors.flatMapping used in combination with Collectors.groupingBy providing intelligent collections of elements.

在本文中,我们将探讨Java 9中新增的两个收集器:Collectors.filteringCollectors.flatMappingCollectors.groupingBy结合使用,提供元素的智能集合。

2. Filtering Collector


The Collectors.filtering is similar to the Stream filter(); it’s used for filtering input elements but used for different scenarios. The Stream’s filter is used in the stream chain whereas the filtering is a Collector which was designed to be used along with groupingBy.

Collectors.filteringStream filter()类似;它用于过滤输入元素,但用于不同的场景。Stream的过滤器在流链中使用,而过滤是一个Collector,被设计为与groupingBy一起使用。

With Stream’s filter, the values are filtered first and then it’s grouped. In this way, the values which are filtered out are gone and there is no trace of it. If we need a trace then we would need to group first and then apply filtering which actually the Collectors.filtering does.


The Collectors.filtering takes a function for filtering the input elements and a collector to collect the filtered elements:


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

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

    assertEquals(1, result.size());

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

    assertEquals(4, result.size());

3. FlatMapping Collector


The Collectors.flatMapping is similar to Collectors.mapping but has a more fine-grained objective. Both the collectors takes a function and a collector where the elements are collected but flatMapping function accepts a Stream of elements which is then accumulated by the collector.


Let’s see the following model class:


class Blog {
    private String authorName;
    private List<String> comments;
    // constructor and getters

Collectors.flatMapping lets us skip intermediate collection and write directly to a single container which is mapped to that group defined by the Collectors.groupingBy:


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 =
       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 =
        Collectors.flatMapping(blog -> blog.getComments().stream(), 

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

The Collectors.mapping maps all grouped author’s comments to the collector’s container i.e. List whereas this intermediate collection is removed with flatMapping as it gives a direct stream of the comment list to be mapped to the collector’s container.


4. Conclusion


This article illustrates the use of the new Collectors introduced in Java9 i.e. Collectors.filtering() and Collectors.flatMapping() used in combination with Collectors.groupingBy().


These Collectors can also be used along with Collectors.partitioningBy() but it only creates two partitions based on conditions and the real power of the collectors isn’t leveraged; hence left out of this tutorial.


The complete source code for the code snippets in this tutorial is available over on GitHub.