这一节所讲的方法都是基于收集collect里面参数Collectors里面的静态方法静态方法。
小插曲:import static java.util.stream.Collectors.*;可以把所有静态方法引入
收集器非常有用,因为它可以简洁而又灵活地定义collect用来生成结果集合的标准。更具体说,对流调用collect方法将对流中的元素发一个归约操作。
本章剩下部分,主要探讨预定义收集器功能,也就是那些可以从Collector类提供的工厂方法创建收集器。主要提供三大功能:
利用counting
public static void testCounting() {
Long collect = menu.stream().collect(counting());
}
maxBy参数接受一个Compartor比较结果。例:
public static void testMaxby() {
Comparator dishComparator = Comparator.comparingInt(Dish::getCalories);
Optional collect = menu.stream().collect(maxBy(dishComparator));
}
Collectors类专门为汇总提供了一个工厂方法:Collectors.summingInt。接受一个对象映射为求和所需int函数。例:
public static void testSummingInt() {
Integer collect = menu.stream().collect(summingInt(Dish::getCalories));
System.out.println(collect);
}
Collectors.summingLong和Collectors.summingDouble方法用法完全一样可以用于求和long和double,求平球输方法averagingLong、averagingDouble、averagingInt。
summarizingInt、summarizingLong、summarizingDouble方法可以数出元素个数、平均数、总和、最大值和最小值。例:
IntSummaryStatistics menuStatistics =
menu.stream().collect(summarizingInt(Dish::getCalories));
joining工厂方法返回的收集器会把中每一个对象应用toString()方法得到的所有字符串
连接成一个字符串。例:把所有的菜肴名称连接起来
public static void testJoining() {
String collect = menu.stream().map(Dish::getName).collect(joining());
System.out.println(collect);
}
重载方法可以添加用什么分隔符
public static void testJoining() {
String collect = menu.stream().map(Dish::getName).collect(joining(","));
System.out.println(collect);
}
前面已经讨论过的收集器,可以用一个reduing工厂方法定义归约过程的特殊情况。例:
public static void testCollectReduing() {
Integer collect = menu.stream().collect(reducing(0, Dish::getCalories, (i, j) -> i + j));
}
它需要三个参数:
第一个参数:归约起始位置
第二个参数:转换成表示所函热量的int
第三个参数:是一个BInaryOperator,将两个项目累计为同一个值。例如对int求和。
java8分组类似于常见数据库分组,我们java8提供了Collectors.groupingBy工厂方法返回的收集器就可以轻松的完成分组。例:
按照菜单类型分组
Map> dishesByType =
menu.stream().collect(groupingBy(Dish::getType));
实现多级分组,可以使用一个由双参数版本的Collectors.groupingBy工厂方法创建收集器,除了普通的分类函数外,还可以接受collector类型的第二个参数。进行二级分组可以把内层的groupingby传递给外层。
例:
public static void testCollecGroupBying() {
Map>> collect = menu.stream().collect(groupingBy(Dish::getType, groupingBy(dish ->
{
if (dish.getCalories() <= 400) return CaloricLevel.DIET;
else if (dish.getCalories() <= 700) return CaloricLevel.NOMAL;
else return CaloricLevel.FAT;
}
)));
System.out.println(collect);
}
传递给第一个groupingBy的第二个收集器可以是任何类型,而不一定是一个groupingBy。例:
Map typesCount = menu.stream().collect(
groupingBy(Dish::getType, counting()));
注意:普通单参数groupingBy单参数其实就是groupbingBy(f,toList)的简写
在举一个例子加深印象
Map> collect1 = menu.stream()
.collect(groupingBy(Dish::getType,
maxBy(Comparator.comparingInt(Dish::getCalories))));
收集器转换成另一种类型可以用:Collectors.collectingAndThen
例:
public static void testCollectAndThen() {
Map collect = menu.stream().collect(groupingBy(Dish::getType,
collectingAndThen(maxBy(Comparator.comparingInt(Dish::getCalories)), Optional::get)));
}
}
collectingAndThen工厂发方法接受两个参数:1、转换收集器(Collector);2、转换函数(Function)。返回值是另一个收集器。
分区的好处在于保留分区函数返回true或false的两套流元素列表。partitioningBy工厂方法有一个重载方法,第二个参数可以传递收集器。
public static void testPartitioningBy() {
Map>> collect = menu.stream().
collect(partitioningBy(Dish::isVegetarian, groupingBy(Dish::getType)));
}
总结:Collectors类的静态工厂方法