1. 概述
Java 8中引入了收集器(Collectors),它们帮助我们将输入元素积累到可变容器,如Map
、List
和Set
中。
本文将探讨Java 9中新增的两个收集器:Collectors.filtering
和Collectors.flatMapping
,它们与Collectors.groupingBy
结合使用,提供智能元素集合功能。
2. filtering
收集器
Collectors.filtering
类似于Stream
的filter()
方法,用于过滤输入元素,但应用场景有所不同。Stream
的filter
通常用于流链中,而filtering
作为收集器设计,常与groupingBy
一起使用。
Stream
的filter
首先过滤值,然后进行分组。这样,被过滤掉的值将不再保留痕迹。如果需要保留过滤后的痕迹,应先分组再过滤,而这正是Collectors.filtering
的作用。
Collectors.filtering
接受一个过滤输入元素的函数和一个收集过滤元素的收集器:
java
复制代码
@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
的函数接收一个元素流,由收集器累积。
来看下面的模型类:
java
复制代码
class Blog { private String authorName; private List<String> comments; // constructor and getters }
Collectors.flatMapping
允许我们跳过中间集合,直接将元素写入单个容器,这个容器是根据Collectors.groupingBy
定义的分组。
java
复制代码
@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. 总结
本篇文章展示了Java 9中新增的收集器Collectors.filtering
和Collectors.flatMapping
如何与Collectors.groupingBy()
一起使用。
这些收集器也可以与Collectors.partitioningBy()
配合,但仅创建基于条件的两个分区,没有充分利用收集器的全部功能,因此本文未涉及这部分内容。