一.收集器
收集器可以简洁而灵活地定义collect用来生成结果集合的标准。更具体地说,对流调用collect方法将对流中的元素触发一个归约操作(由Collector来参数化)。
案例,对一个交易列表按货币分组。
Map<Currency, List<Transaction>> transactionsByCurrencies =
transactions.stream().collect(groupingBy(Transaction::getCurrency));
收集器的功能可以从Collectors类提供的工厂方法(例如groupingBy)创建的收集器。它们主要提供了三大功能:
- 将流元素归约和汇总为一个值
- 元素分组
- 元素分区
二.归约和汇总
- 查找流中的最大值和最小值
Collectors.maxBy
和Collectors.minBy
,来计算流中的最大或最小值。
这两个收集器接收一个Comparator参数来比较流中的元素。
假设你想要找出菜单中热量最高的菜。
//以创建一个Comparator来根据所含热量对菜肴进行比较,并把它传递给Collectors.maxBy
Comparator<Dish> dishCaloriesComparator = Comparator.comparingInt(Dish::getCalories);
Optional<Dish> mostCalorieDish = menu.stream() .collect(maxBy(dishCaloriesComparator));
- 汇总
Collectors类专门为汇总提供了一个工厂方法:
Collectors.summingInt
。它可接受一个把对象映射为求和所需int的函数,并返回一个收集器;该收集器在传递给普通的collect方法后即执行我们需要的汇总操作。
举个例子,样求出菜单中菜肴列表的总热量
//在遍历流时,会把每一道菜都映射为其热量,然后把这个数字累加到一个累加器(这里的初始值0)。
List<Dish> menu = new ArrayList<>();//菜单
menu.add(new Dish(500,"麻婆豆腐"));
menu.add(new Dish(400,"爆炒猪肝"));
menu.add(new Dish(400,"油焖茄子"));
menu.add(new Dish(400,"蒜蓉龙虾"));
int totalCalories = menu.stream().collect(summingInt(Dish::getCalories));
//更简洁可以如下写法,上行代码介绍summingInt
int totalCalories = menu.stream().mapToInt(Dish::getCalories).sum();
Collectors.summingLong
和Collectors.summingDouble
方法的作用完全一样,可以用于求和字段为long或double的情况。
汇总不仅仅是求和;还有Collectors.averagingInt
,连同对应的averagingLong
和averagingDouble
可以计算数值的平均数:
List<Dish> menu = new ArrayList<>();//菜单
menu.add(new Dish(500,"麻婆豆腐"));
menu.add(new Dish(400,"爆炒猪肝"));
menu.add(new Dish(400,"油焖茄子"));
menu.add(new Dish(400,"蒜蓉龙虾"));
double avgCalories = menu.stream().collect(averagingInt(Dish::getCalories));
很多时候,可能想要得到两个或更多这样的结果,而且只需一次操作就可以完成。在这种情况下,你可以使用
summarizingInt
工厂方法返回的收集器。
例如,通过一次summarizing操作你可以就数出菜单中元素的个数,并得到菜肴热量总和、平均值、最大值和最小值:
List<Dish> menu = new ArrayList<>();//菜单
menu.add(new Dish(500,"麻婆豆腐"));
menu.add(new Dish(400,"爆炒猪肝"));
menu.add(new Dish(400,"油焖茄子"));
menu.add(new Dish(400,"蒜蓉龙虾"));
IntSummaryStatistics menuStatistics = menu.stream().collect(Collectors.summarizingInt(Dish::getCalories));
System.out.println(menuStatistics);
这个收集器会把所有这些信息收集到一个叫作IntSummaryStatistics的类里,它提供了方便的取值(getter)方法来访问结果。打印menuStatisticobject会得到以下输出:
IntSummaryStatistics{count=4, sum=1700, min=400, average=425.000000, max=500}
同样,相应的
summarizingLong
和summarizingDouble
工厂方法有相关的LongSummaryStatistics
和DoubleSummaryStatistics
类型,适用于收集的属性是原始类型long或double的情况。
- 连接字符串
joining工厂方法返回的收集器会把对流中每一个对象应用toString方法得到的所有字符串连接成一个字符串。
例如:
List<