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
接受一个过滤输入元素的函数和一个收集过滤元素的收集器:
@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
的函数接收一个元素流,由收集器累积。
来看下面的模型类:
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. 总结
本篇文章展示了Java 9中新增的收集器Collectors.filtering
和Collectors.flatMapping
如何与Collectors.groupingBy()
一起使用。
这些收集器也可以与Collectors.partitioningBy()
配合,但仅创建基于条件的两个分区,没有充分利用收集器的全部功能,因此本文未涉及这部分内容。
本教程中的代码片段完整源代码可在GitHub上获取。