Java 8编写自定义收集器简介

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

Collector<T, A, R>充当流的“接收 ” –流将项(一个接一个)推入收集器,最后应产生一些“ 收集 ”值。 在大多数情况下,这意味着通过累积元素或将流减少到较小的对象(例如, counting()收集器仅计算元素)来构建集合(如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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/362558.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vuex+element 从后台获取数据写导航栏-菜单权限

主要用到 vuex、router.beforeEach、router.addRoutes()。vuex 的使用方法可以看我的另一篇博客&#xff1a;vue笔记&#xff08;四&#xff09;vuex。 顺便安利一个 在线视频转gif图。 因为第一次用到 router.addRoutes()&#xff0c;在做这个需求的时候遇到了很多问题&…

Sql Server全局变量(转)

Sql Server一共提供了30多个全局变量常用:IDENTITY : 返回最后插入行的标识列的列值。ERROR : 返回最后执行的Transact-SQL语句的错误代码。没有错误则为零。ROWCOUNT : 返回受上一语句影响的行数&#xff0c;任何不返回行的语句将这一变量设置为0。DBTS : 返回当前数据库的…

P3393 逃离僵尸岛 最短路dijkstra

题目描述 小a住的国家被僵尸侵略了&#xff01;小a打算逃离到该国唯一的国际空港逃出这个国家。 该国有N个城市&#xff0c;城市之间有道路相连。一共有M条双向道路。保证没有自环和重边。 K个城市已经被僵尸控制了&#xff0c;如果贸然闯入就会被感染TAT...所以不能进入。由其…

jquery 给iframe里的元素添加事件

$("#iframeId").on("load", function(event){//判断 iframe是否加载完成 这一步很重要$("#divId",this.contentDocument).click(function(){//添加点击事件alert("就是这样");}); });更多专业前端知识&#xff0c;请上 【猿2048】www…

JavaFX技巧7:使用CSS颜色常量/派生颜色

在使用FlexCalendarFX时&#xff0c;我不得不定义一组颜色以可视化不同颜色的不同日历的控件。 每个日历不仅提供一种颜色&#xff0c;还提供几种&#xff1a;用于取消选择/选定/悬停状态的背景和文本颜色。 颜色曾在多个地方使用过&#xff0c;但为了简洁起见&#xff0c;我仅…

spring step 1 : 什么是spring

学习一门技术之前还是花点时间来看看这门技术的特点&#xff0c;我们通过使用这种技术能够达到什么效果。 1.spring是什么&#xff1f; 2.spring能够干什么&#xff1f; 3.为什么使用spring&#xff1f; 1.spring是一个开源的框架&#xff0c;主要是由IoC&#xff0c;AOP&#…

文字溢出显示三个点

1、单行溢出 text-overflow: ellipsis; overflow: hidden; white-space: nowrap; width: 90%; 2、多行溢出 overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; 转载于:https://www.cnblogs.co…

import() 动态加载component组件失败

在写 vueelement 从后台获取数据写导航栏 时&#xff0c;当我加载动态路由&#xff0c;import() 总是失败。 假设 path: “/views/Home.vue”&#xff0c;name: “Home”。 一、使用 import() 语法加载组件 参考&#xff1a;“Cookysurongbin”的 解决vue动态路由异步加载im…

JPA /休眠刷新策略初学者指南

介绍 在我之前的文章中&#xff0c;我介绍了实体状态转换 对象关系映射范例。 当刷新当前持久性上下文时&#xff0c;所有管理实体状态转换都将转换为关联的数据库语句。 Hibernate的刷新行为并不总是像人们想象的那么明显。 后写 Hibernate尝试将持久性上下文刷新推迟到最后…

进入登录页时,用户名输入框自动聚焦、按enter键让密码框聚焦,完整输入信息后登录

让element-ui的输入框聚焦的4种方式 思路&#xff1a;&#xff08;可以跳过这一步看完整代码——完整代码&#xff09; 1. 进入页面时&#xff0c;用户名输入框就要获取焦点&#xff0c;使用 自定义指令 聚焦更方便。当然也可以用 ref 在 mounted() 钩子函数中让输入框聚焦。 …

JS的对象及其属性和方法

在JavaScript中是基于对象的编程&#xff0c;而不是完全的面向对象的编程。       那麽什麽是对象呢&#xff1f;如果你学过一些VB的编程&#xff0c;对这个名词一定不会陌生。通俗的说&#xff0c;对象是变量的集合体&#xff0c;对象提供对于数据的一致的组织手段&…

vue-cli安装步骤

vue-cli脚手架模板是基于node下的npm来完成安装的所以首先需要安装node 条件&#xff1a; node在4.以上&#xff0c;npm在3以上 安装 指令&#xff1a; 1、 npm install -g vue-cli在全局下安装vue-cli # 安装 vue-cli npm install -g vue-cli# 初始化 webpack 项目 vue in…

# reverse swap

目录&#xff1a; swap&#xff08;数字、字符串、&#xff09;reverseStringreverseWordsswap /** 借助临时变量 */ function swap(str1, str2) {const temp str1;str1 str2;str2 temp; } /** 解构赋值 */ [a, b] [b, a];/** 对象 */ {a,b} {a:b,b:a} /** 加法 只适用于…

使用Java编写简单的老虎机游戏

无论游戏多么简单或复杂 &#xff0c;Java都能胜任&#xff01; 在这篇文章中&#xff0c;让我们看一下Java编程的初学者如何制作一个简单而功能齐全的老虎机。 老虎机已经存在很长时间了&#xff0c;但是它的娱乐价值似乎并没有减弱。 InterCasino是第一个在1996年向世界提供…

类似flashget的浮动窗口的实现

作者&#xff1a;苍竹先生下载源代码一、简介&#xff1a;象flashget、迅雷、BT等都有浮动窗口&#xff0c;能详细地显示下载的详细信息&#xff0c;该类型的窗口有一下几个特点&#xff1a;1、窗口无标题栏&#xff0c;窗口的大小跟位图一样大。2、前端显示。3、在客户区内按下…

html笔记(二)html4+css2.0(元素类型、css精灵、宽度自适应、BFC、浏览器相关概述、css统筹)

大标题小节一、元素类型1. 元素分类2. 置换和非置换元素3. 元素类型转换二、css精灵三、宽高自适应1. 宽度自适应2. 高度自适应3. 最小高度自适应4. 高度塌陷及解决办法5. 元素的高度自适应屏幕的高度四、BEC概念应用1. 常见定位方案2. 触发BFC3. BFC特性及应用4. BFC概念五、浏…

25.C# 异步调用Web服务

1.创建Web服务 1.1VS新建ASP.Net空Web应用程序 1.2添加Web服务新建项 1.3添加GetWeather方法和相关类 using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Services; using System.EnterpriseServices;namespace WebServ…

css中单位的使用

css中许多的属性都需要添加长度&#xff0c;而长度一般由数字和单位构成&#xff0c;如1px,1.5em,2vh&#xff1b;也可以省略单位&#xff0c;如line-height:1.5,表示行高为字体大小的1.5倍&#xff1b; 长度单位一般也分为相对长度和绝对长度。 &#xff08;一&#xff09;绝…

Office开发程序集版本及部署问题

Office 开发遇到了OFFICE 2003和OFFICE 2007程序集兼容性的问题&#xff0c;使用OFFICE 11.DLL只能适应OFFICE 2003,Office 12.dll 能够兼容Office 2003和Office 2007。 以前部署时&#xff0c;是建议客户安装Office 2003。 今天看到《开发Office的一些应用部署后出现找不到程序…

OSGi:进入微服务架构的门户

在构建可扩展&#xff0c;可靠的分布式系统的背景下&#xff0c;“模块化”和“微服务体系结构”这两个术语如今经常出现。 众所周知&#xff0c;Java平台本身在模块化方面很弱&#xff08; Java 9将通过交付Jigsaw项目来解决这一问题&#xff09;&#xff0c;从而为OSGi和JBos…