java 8流自定义收集器

Java 8引入了收集器的概念。 大多数时候,我们几乎不使用Collectors类中的工厂方法,例如collect(toList())toSet()或其他更有趣的方法,例如counting()groupingBy() 。 实际上,没有多少人真正去研究如何定义和实现收集器。 让我们从分析Collector<T, A, R>真正含义及其工作原理开始。

Collector<T, A, R>充当流的“接收 ” –流将项(一个接一个)推入收集器,最后应产生一些“ 收集 ”值。 在大多数情况下,这意味着通过累积元素或将流减少为更小的内容(例如, counting()很少的元素的toList()收集器)来构建集合(如toList() )。 每个收集器都接受类型T项,并产生类型R聚合(累积)值(例如R = List<T> )。 泛型A简单定义了中间可变数据结构的类型,在此期间,我们将使用它来累积T型项。 类型A可以但不必与R相同-简单来说,我们用来从输入Stream<T>收集项目的可变数据结构可以不同于实际的输出收集/值。 话虽如此,每个收集器都必须实现以下方法:

interface Collector<T,A,R> {Supplier<A>          supplier()BiConsumer<A,T>      acumulator() BinaryOperator<A>    combiner() Function<A,R>        finisher()Set<Characteristics> characteristics()
}
  • supplier()返回一个函数,该函数创建一个累加器实例–可变数据结构,我们将使用该函数来累加类型T输入元素。
  • accumulator()返回一个函数,该函数将累加累加器和类型T一项,即累加累加器。
  • combiner()用于将两个累加器合并为一个。 它在并行执行收集器时使用,首先拆分输入Stream<T>并首先独立收集部分。
  • finisher()使用累加器A并将其转换为R类型的结果值,例如collection。 所有这些听起来都很抽象,所以让我们做一个简单的例子。

显然,Java 8没有为Guava提供ImmutableSet<T>的内置收集器。 但是,创建一个非常简单。 请记住,为了迭代地构建ImmutableSet我们使用ImmutableSet.Builder<T> –这将是我们的累加器。

import com.google.common.collect.ImmutableSet;public class ImmutableSetCollector<T> implements Collector<T, ImmutableSet.Builder<T>, ImmutableSet<T>> {@Overridepublic Supplier<ImmutableSet.Builder<T>> supplier() {return ImmutableSet::builder;}@Overridepublic BiConsumer<ImmutableSet.Builder<T>, T> accumulator() {return (builder, t) -> builder.add(t);}@Overridepublic BinaryOperator<ImmutableSet.Builder<T>> combiner() {return (left, right) -> {left.addAll(right.build());return left;};}@Overridepublic Function<ImmutableSet.Builder<T>, ImmutableSet<T>> finisher() {return ImmutableSet.Builder::build;}@Overridepublic Set<Characteristics> characteristics() {return EnumSet.of(Characteristics.UNORDERED);}
}

首先,仔细研究泛型。 我们的ImmutableSetCollector接受类型T输入元素,因此它适用于任何Stream<T> 。 最后,将产生预期的ImmutableSet<T>ImmutableSet.Builder<T>将成为我们的中间数据结构。

  • supplier()返回创建新ImmutableSet.Builder<T>的函数。 如果您不熟悉Java 8中的lambda,则ImmutableSet::builder() -> ImmutableSet.builder()的简写。
  • accumulator()返回一个函数,该函数采用builder和一个T类型的元素。 它只是将上述元素添加到构建器中。
  • combiner()返回一个函数,该函数将接受两个生成器,并通过将一个中的所有元素添加到另一个中并返回后者来将它们变成一个。 最后finisher()返回一个函数,该函数会将ImmutableSet.Builder<T>转换为ImmutableSet<T> 。 同样,这是以下形式的简写语法: builder -> builder.build()
  • 最后但并非最不重要的一点是, characteristics()告知JDK我们的收集器具有什么功能。 例如,如果ImmutableSet.Builder<T>是线程安全的(不是),我们也可以说Characteristics.CONCURRENT

现在,我们可以使用collect()在所有地方使用自定义收集器:

final ImmutableSet<Integer> set = Arrays.asList(1, 2, 3, 4).stream().collect(new ImmutableSetCollector<>());

但是创建新实例有点冗长,因此我建议创建静态工厂方法,类似于JDK所做的:

public class ImmutableSetCollector<T> implements Collector<T, ImmutableSet.Builder<T>, ImmutableSet<T>> {//...public static <T> Collector<T, ?, ImmutableSet<T>> toImmutableSet() {return new ImmutableSetCollector<>();}
}

从现在开始,我们只需键入以下命令即可充分利用我们的自定义收集器: collect(toImmutableSet()) 。 在第二部分中,我们将学习如何编写更复杂和有用的收集器。

更新资料

@akarazniewicz 指出收藏家只是折叠的冗长实现。 由于我与褶皱之间的爱与恨关系,我不得不对此发表评论。 Java 8中的收集器基本上是Scala中最复杂的折叠类型的面向对象封装,即GenTraversableOnce.aggregate[B](z: ⇒ B)(seqop: (B, A) ⇒ B, combop: (B, B) ⇒ B): Baggregate()就像fold() ,但是需要额外的combop才能将两个B型累加器组合为一个。 将其与收集器进行比较,参数z来自seqop() supplier()seqop()归约运算是一个accumulator()combop是一个combop combiner() 。 用伪代码可以编写:

finisher(seq.aggregate(collector.supplier())(collector.accumulator(), collector.combiner()))

GenTraversableOnce.aggregate()在可能同时进行缩减时使用GenTraversableOnce.aggregate()就像收集器一样)。

翻译自: https://www.javacodegeeks.com/2014/07/introduction-to-writing-custom-collectors-in-java-8.html

java 8流自定义收集器

java 8流自定义收集器_Java 8编写自定义收集器简介相关推荐

  1. java中装饰器_Java设计模式12:装饰器模式

    装饰器模式 装饰器模式又称为包装(Wrapper)模式.装饰器模式以多客户端透明的方式扩展对象的功能,是继承关系的一个替代方案. 装饰器模式的结构 通常给对象添加功能,要么直接修改对象添加相应的功能, ...

  2. java 注解校验_Java开发编写自定义校验注解和校验器

    自定义校验 1).编写一个自定义的校验注解 2).编写一个自定义的校验器 ConstraintValidator 3).关联自定义的校验器和自定义的校验注解 * @Documented * @Cons ...

  3. java 字符流与字节流区别_JAVA 字符流与字节流的区别

    Java 流在处理上分为字符流和字节流.字符流处理的单元为 2 个字节的 Unicode 字符,分别操作字符.字符数组或字符串,而字节流处理单元为 1 个字节,操作字节和字节数组. Java 内用 U ...

  4. java io流读写文件换行_java基础io流——OutputStream和InputStream的故事(温故知新)...

    io流概述: IO流用来处理设备之间的数据传输,上传文件和下载文件,Java对数据的操作是通过流的方式,Java用于操作流的对象都在IO包中. IO流分类 按照数据流向 输入流 读入数据 输出流 写出 ...

  5. java io流学设置编码_Java学习日志(21-2-IO流-基本数据类型与字节数组对象与、编码解码)...

    操作基本数据类型的流对象DataStream /* 可以用于操作基本数据类型数据的流对象 */ import java.io.*; class DataStreamDemo{ public stati ...

  6. java自定义迭代器作用_Java实现的自定义迭代器功能示例

    本文实例讲述了Java实现的自定义迭代器功能.分享给大家供大家参考,具体如下: 编写自己的Iterator,实现Iterator接口,这里多说一句,实现Iterable后,可以用"forea ...

  7. java 反复器_java集合类中的枚举器(反复器)

    在任何集合类中,必须通过某种方法在其中置入对象,再用另一种方法从中取得对象.毕竟,容纳各种各样的对象正是集合的首要任务.在Vector中,addElement()便是我们插入对象采用的方法,而elem ...

  8. java+epub+阅读器_java – 转到epub阅读器页面(PageTurner)

    我必须在epub阅读器中实现Go To Page功能.我尝试在 Page-Turner的源代码中实现此功能,但由于在.epub文件中有多个xhtml,因此我们知道每个章节都有单个xhtml文件,并且按 ...

  9. java歌词解析器_Java swing实现音乐播放器桌面歌词字体变色效果|chu

    最近看到某音乐播放器的桌面歌词如下图 其中字母"U"有两种颜色,突发奇想想模仿一下实现文字变色. 思路:使用两种颜色分别把字符串绘制到两个BufferedImage中,然后根据两种 ...

最新文章

  1. java图片序列化_Java中的强大武器——对象的序列化
  2. 【linux】串口编程(三)——错误处理
  3. 从gitee 下载代码到本地
  4. android 截长图 方法,Android实现截屏与截长图功能
  5. 母版页 中 html 乱码,Thymeleaf使用技巧:使用片段(fragment)实现母版页(Layout)功能...
  6. fdtd中时间监视器怎么放_利用FDTD软件仿真拓扑光子(六)-单向传播仿真与软件设置...
  7. php上传下载excel,PHPExcel 上传下载的示例代码
  8. PMC联手云合作伙伴Canonical加入其Ubuntu OpenStack互通性实验室
  9. VUE颜色选择器插件vColorPicker
  10. 全国30m精度二级分类土地利用数据
  11. wps html嵌入ppt,wps文档怎么插入打开幻灯片 WPS文字添加ppt幻灯片教程
  12. h5页面唤起打电话、发短信功能
  13. 怎么求中位数和分位数 概率密度函数_数理统计第四讲(次序统计量续,伽马分布)...
  14. Bash shell学习笔记(五)
  15. 局域网文件共享的几种方法
  16. 蓝牙耳机哪款性价比高?2023年高性价比蓝牙耳机盘点
  17. 利用Python创建文件
  18. 13种加密与解密算法【一】
  19. 通俗易懂说网络之基础名词及简要介绍(1)
  20. python开发app的软件_如何利用python开发手机app

热门文章

  1. 初一模拟赛总结(2019.3.9)
  2. 一分钟理解Java包装类型
  3. Spring MVC竟然有5种参数绑定的方式?你知道几种?
  4. 汇编语言(十二)之统计小于平均数的个数
  5. Java 0xffffffff隐式类型转换的坑
  6. MySQL date_add()函数​​​​​​​
  7. 学习笔记之ByteBuffer使用和实现以及文件内存映射
  8. 子类可以继承到父类上的注解吗
  9. 漫画:什么是分布式事务
  10. 多线程----join插队