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

最后修改: 2017年 1月 27日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

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

2.过滤收集器

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.

使用Stream的过滤器,价值首先被过滤,然后它被分组。这样一来,被过滤掉的值就消失了,没有任何痕迹。如果我们需要追踪,那么我们就需要先分组,然后再应用过滤,实际上Collectors.filtering就是这样做的。

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

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 Collector

3.FlatMapping收集器

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.

Collectors.flatMappingCollectors.mapping类似,但目标更细。两个收集器都需要一个函数和一个收集元素的收集器,但flatMapping函数接受一个元素的Stream,然后由收集器累积。

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:

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());
}

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.

Collectors.mapping将所有分组的作者评论映射到收集器的容器中,即List,而这个中间集合被flatMapping移除,因为它提供了一个直接将评论列表映射到收集器容器的流。

4. Conclusion

4.结论

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().

本文说明了在Java9中引入的新的Collectors的使用,即Collectors.filtering()Collectors.flatMapping()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.

这些收集器也可以与Collectors.partitioningBy()一起使用,但它只根据条件创建两个分区,收集器的真正力量并没有得到利用;因此,本教程中没有提及。

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

本教程中代码片断的完整源代码可在GitHub上获得