收集器可以简洁而灵活地定义collect用来生成结果集合的标准。更具体地说,对流调用 collect 方法将对流中的元素触发一个归约操作(由Collector来参数化)。一般来说,Collector 会对元素应用一个转换函数(很多时候是不体现任何效果的恒等转换, 例如 toList ),并将结果累积在一个数据结构中,从而产生这一过程的最终输出。下面就来学习那些可以从Collectors 类提供的工厂方法(例如groupingBy)创建的收集器。
Collectors.maxBy 和 Collectors.minBy 来计算流中的最大或最小值。
Optional<Dish> maxDish = Dish.menu.stream(). collect(Collectors.maxBy(Comparator.comparing(Dish::getCalories))); maxDish.ifPresent(System.out::println); Optional<Dish> minDish = Dish.menu.stream(). collect(Collectors.minBy(Comparator.comparing(Dish::getCalories))); minDish.ifPresent(System.out::println);Collectors.summingInt 汇总求和; Collectors.averagingInt 汇总求平均值; Collectors.summarizingInt 汇总所有信息包括数量、求和、平均值、最小值、最大值;
//求总热量 int totalColories = Dish.menu.stream().collect(Collectors.summingInt(Dish::getCalories)); System.out.println(totalColories); //求平均热量 double averageColories = Dish.menu.stream().collect(Collectors.averagingInt(Dish::getCalories)); System.out.println(averageColories); //汇总 IntSummaryStatistics menuStatistics = Dish.menu.stream().collect(Collectors.summarizingInt(Dish::getCalories)); System.out.println(menuStatistics); IntSummaryStatistics{count=9, sum=4300, min=120, average=477.777778, max=800}joining 工厂方法返回的收集器会把对流中每一个对象应用toString方法得到的所有字符串连接成一个字符串。
String menu = Dish.menu.stream().map(Dish::getName).collect(Collectors.joining(",")); System.out.println(menu); //pork,beef,chicken,french fries,rice,season fruit,pizza,prawns,salmonCollectors.reducing 工厂方法是上面所有工厂方法的一般情况,它完全可以实现上述方法的功能。它需要三个参数:
第一个参数是归约操作的起始值,也是流中没有元素时的返回值,所以很显然对于数值和而言0是一个合适的值。 第二个参数是一个 Function,就是具体的取值函数。第三个参数是一个 BinaryOperator,将两个项目累积成一个同类型的值。。 int totalCalories = Dish.menu.stream().collect(Collectors.reducing( 0, Dish::getCalories, (i, j) -> i + j));用Collectors.groupingBy工厂方法返回的收集器可以实现分组任务,分组操作的结果是一个Map,把分组函数返回的值作为映射的键,把流中 所有具有这个分类值的项目的列表作为对应的映射值。
分区是分组的特殊情况:由一个谓词(返回一个布尔值的函数)作为分类函数,它称分区函数。分区函数返回一个布尔值,这意味着得到的分组 Map 的键类型是 Boolean,于是它最多可以分为两组——true是一组,false是一组。分区的好处在于保留了分区函数返回true或false的两套流元素列表。
Map<Boolean, Map<Dish.Type, List<Dish>>> partitioningDish = Dish.menu.stream().collect(Collectors.partitioningBy(Dish::isVegetarian, Collectors.groupingBy(Dish::getType))); System.out.println(partitioningDish); //false={FISH=[prawns, salmon], MEAT=[pork, beef, chicken]}, //true={OTHER=[french fries, rice, season fruit, pizza]}下表展示 Collectors 类的静态工厂方法。
工厂方法返回类型作用toListList<T>把流中所有项目收集到一个 ListtoSetSet<T>把流中所有项目收集到一个 Set,删除重复项toCollectionCollection<T>把流中所有项目收集到给定的供应源创建的集合menuStream.collect(toCollection(), ArrayList::new)countingLong计算流中元素的个数sumIntInteger对流中项目的一个整数属性求和averagingIntDouble计算流中项目 Integer 属性的平均值summarizingIntIntSummaryStatistics收集关于流中项目 Integer 属性的统计值,例如最大、最小、 总和与平均值joiningString连接对流中每个项目调用 toString 方法所生成的字符串collect(joining(", "))maxByOptional<T>一个包裹了流中按照给定比较器选出的最大元素的 Optional, 或如果流为空则为 Optional.empty()minByOptional<T>一个包裹了流中按照给定比较器选出的最小元素的 Optional, 或如果流为空则为 Optional.empty()reducing归约操作产生的类型从一个作为累加器的初始值开始,利用 BinaryOperator 与流 中的元素逐个结合,从而将流归约为单个值累加int totalCalories = menuStream.collect(reducing(0, Dish::getCalories, Integer::sum));collectingAndThen转换函数返回的类型包裹另一个收集器,对其结果应用转换函数int howManyDishes = menuStream.collect(collectingAndThen(toList(), List::size))groupingByMap<K, List<T>>根据项目的一个属性的值对流中的项目作问组,并将属性值作 为结果 Map 的键partitioningByMap<Boolean,List<T>>根据对流中每个项目应用谓词的结果来对项目进行分区