天天看点

用流收集数据

8.1.汇总

(1)Collectors.summingInt。它可接受一 个把对象映射为求和所需int的函数,并返回一个收集器;

(2)Collectors.averagingInt,连同对应的averagingLong和averagingDouble可以计算数值的平均数:

double avgCalories = menu.stream().collect(averagingInt(Dish::getCalories));

(3)summarizing操作你可以就数出菜单中元素的个数

(4)这个收集器会把所有这些信息收集到一个叫作IntSummaryStatistics的类里,它提供了 方便的取值(getter)方法来访问结果,相应的summarizingLong和summarizingDouble工厂方法有相关的LongSummary- Statistics和DoubleSummaryStatistics类型,适用于收集的属性是原始类型long或 double的情况

例如:

IntSummaryStatistics{count=9, sum=4300, min=120, average=477.777778, max=800}

2.连接字符串

joining工厂方法返回的收集器会把对流中每一个对象应用toString方法得到的所有字符

串连接成一个字符串

3.reducing方法创建的收集器来计算你菜单的总热量,如下所示:

int totalCalories = menu.stream().collect(reducing( 0, Dish::getCalories, (i, j) -> i + j));

它需要三个参数。

 第一个参数是归约操作的起始值,也是流中没有元素时的返回值,所以很显然对于数值

和而言0是一个合适的值。

  第二个参数就是你在6.2.2节中使用的函数,将菜肴转换成一个表示其所含热量的int。

  第三个参数是一个BinaryOperator,将两个项目累积成一个同类型的值。这里它就是 对两个int求和。

3.分组

Collectors.groupingBy方法传递了一个Function(以方法引用的形式),它提取了流中每 一道Dish的Dish.Type。我们把这个Function叫作分类函数,因为它用来把流中的元素分成不 同的组

4.多级分组

可以把一个内层groupingBy传递给外层groupingBy

例如,要数一数菜单中每类菜有多少个,可以传递counting收集器作为 groupingBy收集器的第二个参数:

Map<Dish.Type, Long> typesCount = menu.stream().collect( groupingBy(Dish::getType, counting()));

5.分区

分区是分组的特殊情况:由一个谓词(返回一个布尔值的函数)作为分类函数,它称分区函 数。分区函数返回一个布尔值,这意味着得到的分组Map的键类型是Boolean,于是它最多可以 分为两组——true是一组,false是一组

例如:

Map<Boolean,List<Dish> partitionedMenu =

menu.stream().collect(partitioningBy(Dish::isVegetarian));

List<Dish> vegetarianDishes = partitionedMenu.get(true);

7.Collectorsl类的静态工厂方法

工厂方法 返回类型 用于
toList list<T> 把流中所有项目都收集到一个List
使用示例:List <Dish> dishes = menuStream.collect(toList());
toSet Set<T> 把流中所有项目收集到一个Set,删除重复项
使用示例:Set<Dish> dishes = menuStream.collect(toSet());
toCollection Collection<T> 把流中所有项目收集到给定的供应源创建的集合
使用示例:Collection<Dish> dishes = menuStream.collect(toCollection,ArrayList::new);
couting Long 计算流中元素的个数
使用示例:long howmuchDishes = menuStream.collect(counting());
summingInt Integer 对流中项目的一个整数属性求和
使用示例:int totalCalories = menuStream.collect(summingInt(Dish::getCalories));
averagingInt Double 计算流中项目Integer属性的平均值
使用示例:Double avgCalories =menuStream.collect(averagingInt(Dish::getCalories));
summarizingInt IntSummaryStartistics 收集关于流中项目Integer属性的统计值,例如最大、最小、总和与平均值
使用案例:IntSummaryStartistics menustartistics = menustream.collect(summarizingInt(Dish::getCalories));
joining String 连接对流中每个项目调用toString方法所生成的字符串
使用示例:String shortMenu = menustream.map(Dish::getName).collect(joing(","));
maxBy Optional<T> 一个包裹了流中按照给定比较器选出的最大元素Optional,或如果流为空则为Optional.empty()
使用示例:Optional<Dish> fattest = menuStream.collect(maxBy(comparingInt(Dish::getCalories)));
minBy Optional<T> 一个包裹了流中按照给定比较器选出的最小元素Optional,或如果流为空则为Optional.empty()
使用示例:Optional<Dish> lighting = menuStream.collect(minBy(comparingInt(Dish::getCalories)));
reducing 归约操作产生类型 从一个作为累加器的初始值开始,利用BinaryOperator与流中的元素逐个结合,从而将流归约为单个值
使用示例:int totalCalories =menuStream.collect(reducing(0,Dish::getCalories,Integer::sum);
collectingAndThen 转换函数返回类型 包裹一个收集器,对比结果应用转换函数
使用示例:int howManyDishes = menuStream.collect(collectingAndThen(toList(),List::size));
groupingBy Map<k,List<T>> 根据项目的一个属性的值对流中的项目作问组,并将属性值作 为结果 Map 的键
使用示例:Map<Dish.Type,List<Dish> dishesByType = menuStream.collect(groupingBy(Dish::getType));
partitioningBy Map<Boolean,List<t>> 根据对流中每个项目应用谓词的结果来对项目进行分区
使用示例:Map<Boolean,List<Dish>> vegetarianDishes =menuStream.collect(partitioningBy(Dish::isVegetarian));

Collector

接口

public interface Collector<T, A, R> { Supplier<A> supplier(); BiConsumer<A, T> accumulator(); Function<A, R> finisher(); BinaryOperator<A> combiner(); Set<Characteristics> characteristics();

}

本列表适用以下定义。

 T

是流中要收集的项目的泛型。

 A

是累加器的类型,累加器是在收集过程中用于累积部分结果的对象。

 R是收集操作得到的对象(通常但并不一定是集合)的类型。

Collector

接口声明的方法

1.

建立新的结果容器:

supplier

方法

supplier

方法必须返回一个结果为空的

Supplier

,也就是一个无参数函数,在调用时它会

创建一个空的累加器实例,供数据收集过程使用。

public Supplier<List<T>> supplier() { return () -> new ArrayList<T>();

}

2

请注意你也可以只传递一个构造函数引用:

public Supplier<List<T>> supplier(){

return ArrayList::new;

}

将元素添加到结果容器:

accumulator

方法

accumulator

方法会返回执行归约操作的函数

对于

ToListCollector

,这个函数仅仅会把当前项目添加至已经遍历过的项目的 列表:

public BiConsumer<List<T>, T> accumulator() { return (list, item) -> list.add(item);

}

方法引用:

public BiConsumer<List<T>, T> accumulator() { return List::add;

}

对结果容器应用最终转换:

finisher

方法

在遍历完流后,

finisher

方法必须返回在累积过程的最后要调用的一个函数,以便将累加 器对象转换为整个集合操作的最终结果。

finisher

方法只需返回

identity

函数:

public Function<List<T>, List<T>> finisher() { return Function.identity();

}

合并两个结果容器:

combiner

方法