一、概述

Collector是专门用来作为Stream的collect方法的参数的。

public interface Stream extends BaseStream> {

R collect(Collector super T, A, R> collector);

}

而Collectors是作为生产具体Collector的工具类。

二、Collector

Collector主要包含五个参数,它的行为也是由这五个参数来定义的,如下所示:

public interface Collector {

// supplier参数用于生成结果容器,容器类型为A

Supplier supplier();

// accumulator用于消费元素,也就是归纳元素,这里的T就是元素,它会将流中的元素一个一个与结果容器A发生操作

BiConsumer accumulator();

// combiner用于两个两个合并并行执行的线程的执行结果,将其合并为一个最终结果A

BinaryOperator combiner();

// finisher用于将之前整合完的结果R转换成为A

Function finisher();

// characteristics表示当前Collector的特征值,这是个不可变Set

Set characteristics();

}

Collector拥有两个of方法用于生成Collector实例,其中一个拥有上面所有五个参数,另一个四个参数,不包括finisher。

public interface Collector {

// 四参方法,用于生成一个Collector,T代表流中的一个一个元素,R代表最终的结果

public static Collector of(Supplier supplier,

BiConsumer accumulator,

BinaryOperator combiner,

Characteristics... characteristics) {/*...*/}

// 五参方法,用于生成一个Collector,T代表流中的一个一个元素,A代表中间结果,R代表最终结果,finisher用于将A转换为R

public static Collector of(Supplier supplier,

BiConsumer accumulator,

BinaryOperator combiner,

Function finisher,

Characteristics... characteristics) {/*...*/}

}

Characteristics:这个特征值是一个枚举,拥有三个值:CONCURRENT(多线程并行),UNORDERED(无序),IDENTITY_FINISH(无需转换结果)。其中四参of方法中没有finisher参数,所有必有IDENTITY_FINISH特征值。

三、Collectors

Collectors是一个工具类,是JDK预实现Collector的工具类,它内部提供了多种Collector,我们可以直接拿来使用,非常方便。

5.6.1 toCollection

将流中的元素全部放置到一个集合中返回,这里使用Collection,泛指多种集合。

public class CollectorsTest {

public static void toCollectionTest(List list) {

List ll = list.stream().collect(Collectors.toCollection(LinkedList::new));

}

public static void main(String[] args) {

List list = Arrays.asList("123","456","789","1101","212121121","asdaa","3e3e3e","2321eew");

toCollectionTest(list);

}

}

5.6.2 toList

将流中的元素放置到一个列表集合中去。这个列表默认为ArrayList。

public class CollectorsTest {

public static void toListTest(List list) {

List ll = list.stream().collect(Collectors.toList());

}

public static void main(String[] args) {

List list = Arrays.asList("123","456","789","1101","212121121","asdaa","3e3e3e","2321eew");

toListTest(list);

}

}

5.6.3 toSet

将流中的元素放置到一个无序集set中去。默认为HashSet。

public class CollectorsTest {

public static void toSetTest(List list) {

Set ss = list.stream().collect(Collectors.toSet());

}

public static void main(String[] args) {

List list = Arrays.asList("123","456","789","1101","212121121","asdaa","3e3e3e","2321eew");

toSetTest(list);

}

}

5.6.4 joining

joining的目的是将流中的元素全部以字符序列的方式连接到一起,可以指定连接符,甚至是结果的前后缀。

public class CollectorsTest {

public static void joiningTest(List list){

// 无参方法

String s = list.stream().collect(Collectors.joining());

System.out.println(s);

// 指定连接符

String ss = list.stream().collect(Collectors.joining("-"));

System.out.println(ss);

// 指定连接符和前后缀

String sss = list.stream().collect(Collectors.joining("-","S","E"));

System.out.println(sss);

}

public static void main(String[] args) {

List list = Arrays.asList("123","456","789","1101","212121121","asdaa","3e3e3e","2321eew");

joiningTest(list);

}

}

执行结果:

1234567891101212121121asdaa3e3e3e2321eew

123-456-789-1101-212121121-asdaa-3e3e3e-2321eew

S123-456-789-1101-212121121-asdaa-3e3e3e-2321eewE

StringJoiner:这是一个字符串连接器,可以定义连接符和前后缀,正好适用于实现第三种joining方法。

5.6.5 mapping

这个映射是首先对流中的每个元素进行映射,即类型转换,然后再将新元素以给定的Collector进行归纳。

public class CollectorsTest {

public static void mapingTest(List list){

List ll = list.stream().limit(5).collect(Collectors.mapping(Integer::valueOf,Collectors.toList()));

}

public static void main(String[] args) {

List list = Arrays.asList("123","456","789","1101","212121121","asdaa","3e3e3e","2321eew");

mapingTest(list);

}

}

实例中截取字符串列表的前5个元素,将其分别转换为Integer类型,然后放到一个List中返回。

5.6.6 collectingAndThen

该方法是在归纳动作结束之后,对归纳的结果进行再处理。

public class CollectorsTest {

public static void collectingAndThenTest(List list){

int length = list.stream().collect(Collectors.collectingAndThen(Collectors.toList(),e -> e.size()));

System.out.println(length);

}

public static void main(String[] args) {

List list = Arrays.asList("123","456","789","1101","212121121","asdaa","3e3e3e","2321eew");

collectingAndThenTest(list);

}

}

执行结果为:

8

5.6.7 counting

该方法用于计数。

public class CollectorsTest {

public static void countingTest(List list){

long size = list.stream().collect(Collectors.counting());

System.out.println(size);

}

public static void main(String[] args) {

List list = Arrays.asList("123","456","789","1101","212121121","asdaa","3e3e3e","2321eew");

countingTest(list);

}

}

结果:

8

5.6.8 minBy/maxBy

生成一个用于获取最小/最大值的Optional结果的Collector。

public class CollectorsTest {

public static void maxByAndMinByTest(List list){

System.out.println(list.stream().collect(Collectors.maxBy((a,b) -> a.length()-b.length())));

System.out.println(list.stream().collect(Collectors.minBy((a,b) -> a.length()-b.length())));

}

public static void main(String[] args) {

List list = Arrays.asList("123","456","789","1101","212121121","asdaa","3e3e3e","2321eew");

maxByAndMinByTest(list);

}

}

执行结果为:

Optional[212121121]

Optional[123]

5.6.9 summingInt/summingLong/summingDouble

生成一个用于求元素和的Collector,首先通过给定的mapper将元素转换类型,然后再求和。

参数的作用就是将元素转换为指定的类型,最后结果与转换后类型一致。

public class CollectorsTest {

public static void summingTest(List list){

int i = list.stream().limit(3).collect(Collectors.summingInt(Integer::valueOf));

long l = list.stream().limit(3).collect(Collectors.summingLong(Long::valueOf));

double d = list.stream().limit(3).collect(Collectors.summingDouble(Double::valueOf));

System.out.println(i +"\n" +l + "\n" + d);

}

public static void main(String[] args) {

List list = Arrays.asList("123","456","789","1101","212121121","asdaa","3e3e3e","2321eew");

summingTest(list);

}

}

执行结果为:

1368

1368

1368.0

5.6.10 averagingInt/averagingLong/averagingDouble

生成一个用于求元素平均值的Collector,首选通过参数将元素转换为指定的类型。

参数的作用就是将元素转换为指定的类型,求平均值涉及到除法操作,结果一律为Double类型。

public class CollectorsTest {

public static void averagingTest(List list){

double i = list.stream().limit(3).collect(Collectors.averagingInt(Integer::valueOf));

double l = list.stream().limit(3).collect(Collectors.averagingLong(Long::valueOf));

double d = list.stream().limit(3).collect(Collectors.averagingDouble(Double::valueOf));

System.out.println(i +"\n" +l + "\n" + d);

}

public static void main(String[] args) {

List list = Arrays.asList("123","456","789","1101","212121121","asdaa","3e3e3e","2321eew");

averagingTest(list);

}

}

执行结果为:

456.0

456.0

456.0

5.6.11 reducing

reducing方法有三个重载方法,其实是和Stream里的三个reduce方法对应的,二者是可以替换使用的,作用完全一致,也是对流中的元素做统计归纳作用。

public final class Collectors {

// 无初始值的情况,返回一个可以生成Optional结果的Collector

public static Collector> reducing(BinaryOperator op) {/*...*/}

// 有初始值的情况,返回一个可以直接产生结果的Collector

public static Collector reducing(T identity, BinaryOperator op) {/*...*/}

// 有初始值,还有针对元素的处理方案mapper,生成一个可以直接产生结果的Collector,元素在执行结果操作op之前需要先执行mapper进行元素转换操作

public static Collector reducing(U identity,

Function super T, ? extends U> mapper,

BinaryOperator op) {/*...*/}

}

实例:

public class CollectorsTest {

public static void reducingTest(List list){

System.out.println(list.stream().limit(4).map(String::length).collect(Collectors.reducing(Integer::sum)));

System.out.println(list.stream().limit(3).map(String::length).collect(Collectors.reducing(0, Integer::sum)));

System.out.println(list.stream().limit(4).collect(Collectors.reducing(0,String::length,Integer::sum)));

}

public static void main(String[] args) {

List list = Arrays.asList("123","456","789","1101","212121121","asdaa","3e3e3e","2321eew");

reducingTest(list);

}

}

Optional[13]

9

13

5.6.12 groupingBy

这个方法是用于生成一个拥有分组功能的Collector,它也有三个重载方法:

public final class Collectors {

// 只需一个分组参数classifier,内部自动将结果保存到一个map中,每个map的键为?类型(即classifier的结果类型),值为一个list,这个list中保存在属于这个组的元素。

public static Collector>> groupingBy(

Function super T, ? extends K> classifier) {/*...*/}

// 在上面方法的基础上增加了对流中元素的处理方式的Collector,比如上面的默认的处理方法就是Collectors.toList()

public static Collector> groupingBy(

Function super T, ? extends K> classifier,Collector super T, A, D> downstream) {/*...*/}

// 在第二个方法的基础上再添加了结果Map的生成方法。

public static >

Collector groupingBy(Function super T, ? extends K> classifier,

Supplier mapFactory,

Collector super T, A, D> downstream) {/*...*/}

}

实例:

public class CollectorsTest {

public static void groupingByTest(List list){

Map> s = list.stream().collect(Collectors.groupingBy(String::length));

Map> ss = list.stream().collect(Collectors.groupingBy(String::length, Collectors.toList()));

Map> sss = list.stream().collect(Collectors.groupingBy(String::length,HashMap::new,Collectors.toSet()));

System.out.println(s.toString() + "\n" + ss.toString() + "\n" + sss.toString());

}

public static void main(String[] args) {

List list = Arrays.asList("123","456","789","1101","212121121","asdaa","3e3e3e","2321eew");

groupingByTest(list);

}

}

执行结果为:

{3=[123, 456, 789], 4=[1101], 5=[asdaa], 6=[3e3e3e], 7=[2321eew], 9=[212121121]}

{3=[123, 456, 789], 4=[1101], 5=[asdaa], 6=[3e3e3e], 7=[2321eew], 9=[212121121]}

{3=[123, 456, 789], 4=[1101], 5=[asdaa], 6=[3e3e3e], 7=[2321eew], 9=[212121121]}

groupingBy方法还有并发版的groupingByConcurrent,功能基本一致,只是返回的Collector是并行的。

5.6.13 partitioningBy

该方法将流中的元素按照给定的校验规则的结果分为两个部分,放到一个map中返回,map的键是Boolean类型,值为元素的列表List。

该方法有两个重载方法:

public final class Collectors {

// 只需一个校验参数predicate

public static

Collector>> partitioningBy(Predicate super T> predicate) {/*...*/}

// 在上面方法的基础上增加了对流中元素的处理方式的Collector,比如上面的默认的处理方法就是Collectors.toList()

public static

Collector> partitioningBy(Predicate super T> predicate,

Collector super T, A, D> downstream) {/*...*/}

}

实例:

public class CollectorsTest {

public static void partitioningByTest(List list){

Map> map = list.stream().collect(Collectors.partitioningBy(e -> e.length()>5));

Map> map2 = list.stream().collect(Collectors.partitioningBy(e -> e.length()>6,Collectors.toSet()));

System.out.println(map.toString() + "\n" + map2.toString());

}

public static void main(String[] args) {

List list = Arrays.asList("123","456","789","1101","212121121","asdaa","3e3e3e","2321eew");

partitioningByTest(list);

}

}

执行结果:

{false=[123, 456, 789, 1101, asdaa], true=[212121121, 3e3e3e, 2321eew]}

{false=[123, 456, 1101, 789, 3e3e3e, asdaa], true=[212121121, 2321eew]}

5.6.14 toMap

toMap方法是根据给定的键生成器和值生成器生成的键和值保存到一个map中返回,键和值的生成都依赖于元素,可以指定出现重复键时的处理方案和保存结果的map。

public final class Collectors {

// 指定键和值的生成方式keyMapper和valueMapper

public static

Collector> toMap(Function super T, ? extends K> keyMapper,

Function super T, ? extends U> valueMapper) {/*...*/}

// 在上面方法的基础上增加了对键发生重复时处理方式的mergeFunction,比如上面的默认的处理方法就是抛出异常

public static

Collector> toMap(Function super T, ? extends K> keyMapper,

Function super T, ? extends U> valueMapper,

BinaryOperator mergeFunction) {/*...*/}

// 在第二个方法的基础上再添加了结果Map的生成方法。

public static >

Collector toMap(Function super T, ? extends K> keyMapper,

Function super T, ? extends U> valueMapper,

BinaryOperator mergeFunction,

Supplier mapSupplier) {/*...*/}

}

实例:

public class CollectorsTest {

public static void toMapTest(List list){

Map map = list.stream().limit(3).collect(Collectors.toMap(e -> e.substring(0,1),e -> e));

Map map1 = list.stream().collect(Collectors.toMap(e -> e.substring(0,1),e->e,(a,b)-> b));

Map map2 = list.stream().collect(Collectors.toMap(e -> e.substring(0,1),e->e,(a,b)-> b,HashMap::new));

System.out.println(map.toString() + "\n" + map1.toString() + "\n" + map2.toString());

}

public static void main(String[] args) {

List list = Arrays.asList("123","456","789","1101","212121121","asdaa","3e3e3e","2321eew");

toMapTest(list);

}

}

执行结果:

{1=123, 4=456, 7=789}

{a=asdaa, 1=1101, 2=2321eew, 3=3e3e3e, 4=456, 7=789}

{a=asdaa, 1=1101, 2=2321eew, 3=3e3e3e, 4=456, 7=789}

第一种方式中,如果不添加limit限制,就会抛出异常。

还有并发的版本:toConcurrentMap,同样三种重载方法,与toMap基本一致,只是它最后使用的map是并发Map:ConcurrentHashMap。

5.6.15 summarizingInt/summarizingLong/summarizingDouble

这三个方法适用于汇总的,返回值分别是IntSummaryStatistics,LongSummaryStatistics,DoubleSummaryStatistics。

在这些返回值中包含有流中元素的指定结果的数量、和、最大值、最小值、平均值。所有仅仅针对数值结果。

public class CollectorsTest {

public static void summarizingTest(List list){

IntSummaryStatistics intSummary = list.stream().collect(Collectors.summarizingInt(String::length));

LongSummaryStatistics longSummary = list.stream().limit(4).collect(Collectors.summarizingLong(Long::valueOf));

DoubleSummaryStatistics doubleSummary = list.stream().limit(3).collect(Collectors.summarizingDouble(Double::valueOf));

System.out.println(intSummary.toString() + "\n" + longSummary.toString() + "\n" + doubleSummary.toString());

}

public static void main(String[] args) {

List list = Arrays.asList("123","456","789","1101","212121121","asdaa","3e3e3e","2321eew");

summarizingTest(list);

}

}

执行结果:

IntSummaryStatistics{count=8, sum=40, min=3, average=5.000000, max=9}

LongSummaryStatistics{count=4, sum=2469, min=123, average=617.250000, max=1101}

DoubleSummaryStatistics{count=3, sum=1368.000000, min=123.000000, average=456.000000, max=789.000000}

最后我们可以从返回的汇总实例中获取到想要的汇总结果。

四、总结

整个Collectors工具类就是在为Collector服务,用于创建各种不同的Collector。部分功能与Stream中的方法重合了,为了简化代码,完全不必采用Collectors实现,优先Stream方法。

参考:

collectors 求和_Java基础系列-Collector和Collectors相关推荐

  1. Java基础系列-Collector和Collectors

    原创文章,转载请标注出处:<Java基础系列-Collector和Collectors> 一.概述 Collector是专门用来作为Stream的collect方法的参数的. public ...

  2. java代码讲解_Java基础系列-代码块详解

    注:本文出自博主 Chloneda:个人博客 | 博客园 | Github | Gitee | 知乎 前言 Java基础系列,尽量采用通俗易懂.循序渐进的方式,让大家真正理解Java基础知识! 代码块 ...

  3. pgsql中float4导致java程序精度丢失_Java基础系列02

    注释 Java中支持三种注释:1.单行注释以//开始换行结束.2.多行注释以/*开始,以*/结束.3.说明注释以/**开始,以*/结束. 关键字 关键字:是指在程序中,Java已经定义好的单词,具有特 ...

  4. java 5 多线程_Java基础系列五、多线程

    1.什么是进程?什么是线程? 进程概念:在计算机中运行的软件,是操作系统中最基础的组成部分 .进程是容器,里面装的都是线程. 线程概念:就是运行在进程中的一段代码,是进程中最小组织单元. 注意: 1. ...

  5. java throw 接口_Java基础系列-throw、throws关键字

    一.概述 throw和throws就是异常相关的关键字,在java中异常机制是一个非常重要的机制,我们需要重点掌握. 既然说到了异常,简单描述下异常机制很有必要,这也对后文的讲述提供前提. 二.Jav ...

  6. java 反射与泛型_Java基础系列 - 泛型和反射机制

    package com.test5; import java.lang.reflect.Field; import java.lang.reflect.Method; /** * Java泛型和反射机 ...

  7. java必学_Java基础系列之初识JAVA

    工欲善其事必先利其器,在学习Java之初,大家一定要先了解下java的历史,以及找到一个适合自己的学习方法!很多同学在自学或者听课之初,完全不建议你直接使用一些IDE工具去写程序!自己先动手完全是很有 ...

  8. java 父类构造函数_Java基础系列 - 子类继承父类,调用父类的构造函数

    package com.test7; public class test7 { public static void main(String[] args) { Son son = new Son(1 ...

  9. java泛型常用特点_Java基础系列(3)Java泛型知多少?

    不积跬步,无以至千里:不积小流,无以成江海 什么是泛型?为什么要使用泛型? 泛型,即"参数化类型".一提到参数,最熟悉的就是定义方法时有形参,然后调用此方法时传递实参.那么参数化类 ...

最新文章

  1. luogu2467/bzoj1925 地精部落 (dp)
  2. oracle job 事务提交,Oracle dbms_job.submit用法
  3. 针对移动互联网应用的网络建设和优化
  4. lucene 查询示例_高级Lucene查询示例
  5. HDU 1525 类Bash博弈
  6. 字符串处理 —— 最大最小表示法
  7. Ceres Solver: 高效的非线性优化库(二)实战篇
  8. Ubuntu 16.04 安裝chrome
  9. 爬虫爬取数据时如何快速换IP?极光IP轻松搞定
  10. 时间管理之-----《暗时间》-刘未鹏
  11. 语言缩写c-a,各国语言缩写及语言代码查询
  12. 软考备考-系统构架师-21-系统架构师考纲整理
  13. DEJA_VU3D - Cesium功能集 之 007-军事标绘系列一:简单箭头
  14. 51单片机 16路抢答 显示在 点阵 普中 V2
  15. 面对裁员潮,程序员如何安身立命
  16. 数据生产力崛起:新动能 新治理 - 摘要
  17. 51单片机(STC)串口无阻塞发送函数
  18. Qt面试笔试题问答经验总结
  19. 优学院计算机基础网课答案,最新网课答案2020优学院大学计算机基础
  20. EasyExcel 设置边框样式(线条类型和线条颜色)

热门文章

  1. Qt 设计师-Qt Designer基础控件介绍
  2. 改变mathtype插入公式编号格式
  3. 元宇宙:一场游戏世界的革命
  4. 整数二进制补码的数学原理(two's complement)
  5. 【网络】Wireshark分析Netty建链过程( tcp三次握手、osi模型)
  6. viola jones人脸检测原理
  7. 对不起, 老师 我把知识还给您了 呜呜呜 ......面试杀手-double精度问题深入剖析 进制转换
  8. python中输出1到1000以内的_Python程序-输出1000以内素数
  9. 双十一临近,京东出奇招,摆摊卖娃娃
  10. linux内核nomodeset,修复因显卡不支持而引起Ubuntu live USB无法启动的问题