Collector接口包含了一系列方法,为实现具体的归约操作(即收集器)提供了范本。我们已经看过了Collector接口中实现的许多收集器(由Collector接口的工具类Collectors提供),例如toList()或groupingBy()。

这也意味着你可以为Collector接口提供自己的实现,从而自由地创建自定义归约操作。

要实现自定义收集器,只需要实现java.util.stream.Collector<T, A, R>接口即可.

Collector接口的声明如下:

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

泛型介绍

  • T:stream在调用collect方法收集前的数据类型

  • A:A是T的累加器,遍历T的时候,会把T按照一定的方式添加到A中,换句话说就是把一些T通过一种方式变成A

  • R:R可以看成是A的累加器,是最终的结果,是把A汇聚之后的数据类型,换句话说就是把一些A通过一种方式变成R

接口介绍

  • supplier: 怎么创建一个累加器

  • accumulator:怎么把一个对象添加到累加器中

  • combiner: 怎么把一个累加器和另一个累加器合并起来,此方法并行时才会调用

  • finisher: 怎么把A转化为R

  • characteristics: 特征值,告诉collect方法在执行归约操作的时候可以应用哪些优化

Characteristics

包含三个项目的枚举:

  • UNORDERED:归约结果不受流中项目的遍历和累积顺序的影响

  • CONCURRENT:accumulator函数可以从多个线程同时调用,且该收集器可以并行归约流。如果收集器没有标为UNORDERED, 那它仅在用于无序数据源时才可以并行归约。

  • IDENTITY_FINISH:这表明完成器方法返回的函数是一个恒等函数,可以跳过。这种情况下,累加器对象将会直接用做归约过程的最终结果。这也意味着,将累加器A不加检查地转换为结果R是安全的。

当Collector设置为IDENTITY_FINISH,finisher方法不会调用,因为不用再类型转换了,中间数据类型就是最终的数据类型。

Stream#collect()源码分析

下面的Stream的实现类ReferencePipeline的collect方法的源码

public final <R, A> R collect(Collector<? super P_OUT, A, R> collector) { // @1A container;if (isParallel()&& (collector.characteristics().contains(Collector.Characteristics.CONCURRENT))&& (!isOrdered() || collector.characteristics().contains(Collector.Characteristics.UNORDERED))) { // @2container = collector.supplier().get(); // @3BiConsumer<A, ? super P_OUT> accumulator = collector.accumulator();forEach(u -> accumulator.accept(container, u));}else {container = evaluate(ReduceOps.makeRef(collector)); // @4}return collector.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)? (R) container: collector.finisher().apply(container); // @5
}
  • 代码@1:函数声明,该方法返回的结果类型为R,传入的行为参数接口为Collector。

  • 代码@2:判断是否符合并行化累积与规约的条件。

    • 是否是并行流,Stream.stream()方法的流是非并行化流,如果要支持并行化执行,需要使用Stream.parallelStream()方法。

    • Collector(收集器,行为化参数)中收集器行为集合中是否包含Characteristics.CONCURRENT(并行执行),如果不包含该行为,则不支持并行执行。

    • 原始流是否有顺序或者收集器的行为集合中明确包含Characteristics.UNORDERED(不要求顺序性)。

    • 上述三个条件必须同时满足,才能并行执行,否则串行执行。

  • 代码@3:并行执行收集动作。

  • 代码@4:串行执行收集动作。

  • 代码@5:如果收集器收集行为集合中包含Characteristics.IDENTITY_FINISH,则直接返回原始值,否则使用Collector.finishier()方式对计算的值进行函数式计算。

自定义toList

package com.morris.java8.collector;import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collector;public class ToListCollector<T> implements Collector<T, List<T>, List<T>> {@Overridepublic Supplier<List<T>> supplier() {return ArrayList::new;}@Overridepublic BiConsumer<List<T>, T> accumulator() {return List::add;}@Overridepublic BinaryOperator<List<T>> combiner() {return (left, right) -> {left.addAll(right);return left;};}@Overridepublic Function<List<T>, List<T>> finisher() {return Function.identity();}@Overridepublic Set<Characteristics> characteristics() {return Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.IDENTITY_FINISH));}public static void main(String[] args) {List<Dish> dishList = Dish.createList().stream().filter(Dish::isVegetarian).collect(new ToListCollector<>());System.out.println(dishList);}
}

自定义joining

package com.morris.java8.collector;import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collector;public class JoiningCollector implements Collector<String, StringBuilder, String> {private String seperator = ",";public JoiningCollector() {}public JoiningCollector(String seperator) {this.seperator = seperator;}@Overridepublic Supplier<StringBuilder> supplier() {return StringBuilder::new;}@Overridepublic BiConsumer<StringBuilder, String> accumulator() {return (sb, str) -> sb.append(str).append(seperator);}@Overridepublic BinaryOperator<StringBuilder> combiner() {return StringBuilder::append;}@Overridepublic Function<StringBuilder, String> finisher() {return c -> {String ret = c.toString();if (ret.endsWith(seperator)) {return ret.substring(0, ret.length() - 1);}return ret;};}@Overridepublic Set<Characteristics> characteristics() {return new HashSet<>();}public static void main(String[] args) {String collect = Arrays.asList("hello", "world", "java", "stream").stream().collect(new JoiningCollector("|"));System.out.println(collect);}}

【java8】自定义Collector相关推荐

  1. Java8中Collector详解及自定义Collector

    文章目录 1.Collector介绍 2.Collector约束 3.Collector接口方法 4.理解Collector接口声明的方法 5.整合自定义Collector 6.使用collect方法 ...

  2. ### java8之collector详解,以及结合toMap,sorted,groupingBy使用例子

    最近接触到java8的collector功能,网上查了下资料学习,这里记录一下. collect方法,它是一个能够把stream管道中的结果集装进一个List集合的终极操作. collect是一个把s ...

  3. java 自定义 operator_java8 自定义Collector

    package com.lgx.jdk8.part02; import java.util.*; import java.util.function.BiConsumer; import java.u ...

  4. Java 8 - 自定义Collector

    文章目录 Pre Collector接口声明的方法 理解 Collector接口中声明的方法 1.建立新的结果容器: supplier 方法 2.将元素添加到结果容器: accumulator 方法 ...

  5. Java8自定义条件让集合分组

    ** 将一个指定类型对象的集合按照自定义的一个操作分组: 每组对应一个List.最终返回结果类型是:List<List<T>> @param <T> */ stat ...

  6. Java8 - 自定义实现体会Future的原理

    文章目录 自定义Future 同步方式 自定义Future package com.artisan.java8.testFuture.customFuture;public interface Cus ...

  7. [ lucene扩展 ] 自定义Collector实现统计功能

    对于lucene的统计,我基本放弃使用factedSearch了,效率不高,而且两套索引总觉得有点臃肿! 这次我们通过改造Collector,实现简单的统计功能.经过测试,对几十万的统计还是比较快的. ...

  8. Java8 - 自定义实现体会CompletableFuture的原理

    文章目录 Code Code Future 接口 的局限性有很多,其中一个就是需要主动的去询问是否完成,如果等子线程的任务完成以后,通知我,那岂不是更好? public class FutureInA ...

  9. java8自定义收集器_使用自定义收集器进行Java 8分组?

    我有以下课程. class Person { String name; LocalDate birthday; Sex gender; String emailAddress; public int ...

最新文章

  1. ios5中apple增加了解析JSON的api——NSJSONSerialization。
  2. 防止js全局变量污染方法总结-待续
  3. [C#参考]锁定lock
  4. Rhel7 IPV6配置
  5. Qt 中pro文件换行注意的问题
  6. c++继承父类的子类,如何调用父类的同名函数?
  7. 关于mysql单表支持的最大大小
  8. Tesla对德国政府的审批流程表示受够了
  9. Spring : 异步注解 @EnableAsync 和 @Async
  10. 球球大作战c语言源代码,球球大作战,源码分享
  11. python判断英文字母_python判断字符串是否包含字母
  12. 此流上不支持超时。_10分钟了解线程池,阿里再也不担心我线程池资源耗尽了...
  13. CentOS下安装php gd库报错Error: php56w-common conflicts with php-common-5.3.3-48.el6_8.x86_64
  14. 46多项式01——一元多项式和运算
  15. 【Sql Server】经典SQL语句大全
  16. Unity简单实现调用电脑打印机打印图片功能
  17. 硬盘安装win10,笔者教你如何一步步从硬盘安装win10系统
  18. 清晰理解precision(精确度)和recall(召回度)
  19. [开心学php100天]第六天:用php玩转页面(基础篇)
  20. python3 url解析 urllib.parse.urlparse 库简介

热门文章

  1. 【小知识】微软(Microsoft)的win7 SP1补丁,细分版本CHK和FRE的区别
  2. 如何高效阅读论文,养成良好的习惯(一))
  3. 开启springcloud全家桶2:初探Hystrix原理与实践
  4. VC利用WORD替换功能打印发票
  5. echarts图表坐标轴数据标签添加下划线
  6. Python 银行信用卡客户流失预测(kaggle)
  7. 全网最详细的Hadoop大数据集群搭建并进行项目分析(基于完全分布式)---终结篇
  8. matlab程序设计例题,MATLAB程序设计例题及答案.pdf
  9. tinyxml和rapidxml
  10. dcom 配置 我的电脑 显示红色箭头