一种通用的、从流生成复杂值的结构,只要把它传给collect方法,所有的流就都可以使用它了。
标准类库已经提供了一些有用的收集器,下面示例代码中的收集器都是从java.util.stream.Collectors类中导入的。
转换成其他集合
使用Collectors.toList,还有toSet、toCollection等,这里不需要指定具体的类型,Stream类库在背后自动挑选合适的类型。
如果需要指定具体的类型,可以使用toCollection,用定制的集合收集元素
// 使用TreeSet收集元素
Stream.of(1, 2, 3).collect(Collectors.toCollection(TreeSet::new));
转换成值
可以利用收集器让流生成一个值
// 计算每个元素加1后的平均值
Stream.of(1, 2, 3).collect(Collectors.averagingInt(number -> number + 1));
数据分块
另外一种常用的流操作是将其分解为两个集合。可以使用收集器partitioningBy,它接收一个流,并将其分成两部分(使用Predicate对象判断一个元素应该属于哪个部分,并根据布尔值返回一个map到列表)
// 分别找出奇数和偶数
Map<Boolean, List<Integer>> collect =
Stream.of(1, 2, 3, 4).collect(Collectors.partitioningBy(number -> number % 2 == 0));
数据分组
数据分组是一种更自然的分割数据操作,与将数据分成true和false不同,可以使用任意值对数据分组。使用groupingBy可以对流进行分组
List<Track> tracks = Arrays.asList(new Track("Bakal", 524),
new Track("Violets for Your Furs", 378),
new Track("Bakal", 451));
// 根据名称来分组
Map<String, List<Track>> collect =
tracks.stream().collect(Collectors.groupingBy(track -> track.getName()));
// 使用方法应用优化
Map<String, List<Track>> collect =
tracks.stream().collect(Collectors.groupingBy(Track::getName));
字符串
很多时候,收集流中的数据都是为了在最后生成一个字符串。可以使用joining
List<Track> tracks = Arrays.asList(new Track("Bakal", 524),
new Track("Violets for Your Furs", 378),
new Track("Bakal", 451));
// 使用map提取名称,使用joining得到一个字符串,允许用户指定分割符、前缀、后缀
String collect = tracks.stream()
.map(Track::getName)
.collect(Collectors.joining(", ", "[", "]"));
组合收集器
可以使用第二个收集器,用以收集最终结果的一个子集,这些收集器叫做下游收集器。收集器是生成最终结果的一剂配方,下游收集器是生成部分结果的配方,主收集器中会用到下游收集器。
List<Track> tracks = Arrays.asList(new Track("Bakal", 524),
new Track("Violets for Your Furs", 378),
new Track("Bakal", 451));
// 计算每个分组下的数量
Map<String, Long> collect =
tracks.stream()
.collect(Collectors.groupingBy(Track::getName, Collectors.counting()));
自定义收集器
除此之外,还可以自定义收集器,这里不再展开
练习
使用Map的computeIfAbsent方法高效计算斐波那契数列
public class Fibonacci {
private static final Map<Integer,Long> cache;
static {
cache = new HashMap<>();
cache.put(0, 0L);
cache.put(1, 1L);
}
public static long fibonacci(int x) {
// 当cache中有时,则直接计算,如果没有则计算并放入cache中
return cache.computeIfAbsent(x, n -> fibonacci(n-1) + fibonacci(n-2));
}
public static void main(String[] args) {
System.out.println(fibonacci(10));
cache.forEach((key, value) -> {
System.out.println(key + ": " + value);
});
}
}