collectors 求和_JDK Collectors与Collector

起因:前段时间开始了解并使用Stream流式计算,其中collect()的方法使用很多情况下需要去百度。又因为它的名字与之前写的集合框架工具类JDK Collections工具类 比较像。所以一直想要写一篇博客来记录和学习一下。

Collectors与Collector位于java.util.stream包下,为stream流式计算提供方便的。

1.Collector(interface)

Collector意为收集器,在JDK文档中的描述为:将输入元素累加到可变结果容器中,可选地在所有输入元素被处理之后将累加结果转换成最终表示。 还原操作可以顺序还是并行执行。 Collectors类提供了许多常见的可变减少的实现。

Collector由四个函数来指定,这四个函数一起工作以将条目累加到可变结果容器中,并且可选地对结果进行最终转换。 他们是:

创建新的结果容器( Supplier supplier();)--供给型接口

将新的数据元素并入结果容器( BiConsumer accumulator();)--消费型接口

将两个结果容器组合成一个( BinaryOperator combiner(); )--BiFunction 两个参数的函数式接口

在容器上执行可选的最终变换( Function finisher();)--函数式接口

总结:实现该接口,重写该方法

2.Collectors(final class)

Collectors为Collector的工具类,实现了Collector,内部有很多方法返回值为Collector类型。在stream链式编程中, R collect(Collector super T, A, R> collector)方法的参数为collector,可以使用collectors的方法来实现我们想要的操作。

转换成其他集合

toList

toSet

toCollection

值得我们注意的是,看Collectors的源码,因为其接受的函数参数必须继承于Collection,也就是意味着Collection并不能转换所有的继承类,最明显的就是不能通过toCollection转换成Map

toMap

如果生成一个Map,我们需要调用toMap方法。由于Map中有Key和Value这两个值,故该方法与toSet、toList等的处理方式是不一样的。toMap最少应接受两个参数,一个用来生成key,另外一个用来生成value。

转成值

averagingDouble:求平均值,Stream的元素类型为double

averagingInt:求平均值,Stream的元素类型为int

averagingLong:求平均值,Stream的元素类型为long

counting:Stream的元素个数

maxBy:在指定条件下的,Stream的最大元素

minBy:在指定条件下的,Stream的最小元素

reducing: reduce操作

summarizingDouble:统计Stream的数据(double)状态,其中包括count,min,max,sum和平均。

summarizingInt:统计Stream的数据(int)状态,其中包括count,min,max,sum和平均。

summarizingLong:统计Stream的数据(long)状态,其中包括count,min,max,sum和平均。

summingDouble:求和,Stream的元素类型为double

summingInt:求和,Stream的元素类型为int

summingLong:求和,Stream的元素类型为long

分割数据块

collect的一个常用操作将Stream分解成两个集合。假如一个数字的Stream,我们可能希望将其分割成两个集合,一个是偶数集合,另外一个是奇数集合。我们首先想到的就是过滤操作,通过两次过滤操作,很简单的就完成了我们的需求。

但是这样操作起来有问题。首先,为了执行两次过滤操作,需要有两个流。其次,如果过滤操作复杂,每个流上都要执行这样的操作, 代码也会变得冗余。

这里我们就不得不说Collectors库中的partitioningBy方法,它接受一个流,并将其分成两部分:使用Predicate对象,指定条件并判断一个元素应该属于哪个部分,并根据布尔值返回一个Map到列表。因此对于key为true所对应的List中的元素,满足Predicate对象中指定的条件;同样,key为false所对应的List中的元素,不满足Predicate对象中指定的条件

这样,使用partitioningBy,我们就可以将数字的Stream分解成奇数集合和偶数集合了。

Map> collectParti = Stream.of(1, 2, 3, 4)

.collect(Collectors.partitioningBy(it -> it % 2 == 0));

System.out.println("collectParti : " + collectParti);

// 打印结果

// collectParti : {false=[1, 3], true=[2, 4]}

看groupingBy和partitioningBy的例子,他们的效果都是一样的,都是将Stream的数据进行了分割处理并返回一个Map。可能举的例子给你带来了误区,实际上他们两个完全是不一样的。

partitioningBy是根据指定条件,将Stream分割,返回的Map为Map

字符串

这里我们将使用 Collectors.joining 收集Stream中的值,该方法可以方便地将Stream得到一个字符串。joining函数接受三个参数,分别表示允(用以分隔元素)、前缀和后缀。

组合Collector

在数据分组时,我们是得到的分组后的数据列表 collectGroup : {false=[1, 2, 3], true=[4]}。如果我们的要求更高点,我们不需要分组后的列表,只要得到分组后列表的个数就好了。

这时候,很多人下意识的都会想到,便利Map就好了,然后使用list.size(),就可以轻松的得到各个分组的列表个数。

// 分割数据块

Map> collectParti = Stream.of(1, 2, 3, 4)

.collect(Collectors.partitioningBy(it -> it % 2 == 0));

Map mapSize = new HashMap<>();

collectParti.entrySet()

.forEach(entry -> mapSize.put(entry.getKey(), entry.getValue().size()));

System.out.println("mapSize : " + mapSize);

// 打印结果

// mapSize : {false=2, true=2}

在partitioningBy方法中,有这么一个变形:

Map partiCount = Stream.of(1, 2, 3, 4)

.collect(Collectors.partitioningBy(it -> it.intValue() % 2 == 0,

Collectors.counting()));

System.out.println("partiCount: " + partiCount);

// 打印结果

// partiCount: {false=2, true=2}

在partitioningBy方法中,我们不仅传递了条件函数,同时传入了第二个收集器,用以收集最终结果的一个子集,这些收集器叫作下游收集器。收集器是生成最终结果的一剂配方,下游收集器则是生成部分结果的配方,主收集器中会用到下游收集器。这种组合使用收集器的方式, 使得它们在 Stream 类库中的作用更加强大。

那些为基本类型特殊定制的函数,如averagingInt、summarizingLong等,事实上和调用特殊Stream上的方法是等价的,加上它们是为了将它们当作下游收集器来使用的。

不要以为每天把功能完成了就行了,这种思想是要不得的,互勉~!

你可能感兴趣的:(collectors,求和)