累积:轻松自定义Java收集器

Accumulative是针对Collector<T, A, R>的中间累积类型A提出的接口Collector<T, A, R>以使定义自定义Java Collector更加容易。

介绍

如果您曾经使用过Java Stream ,那么很可能使用了一些Collector ,例如:

  • Collectors.toList
  • Collectors.toMap

但是你有没有使用过……

  1. 组成的 Collector
    • 它使用另一个 Collector作为参数,例如: Collectors.collectingAndThen
  2. 定制 Collector
    • 其功能在Collector.of明确指定。

这篇文章是关于custom Collector的。

集电极

让我们回想一下Collector合同的本质 (我的评论):

 /** * @param <T> (input) element type * @param <A> (intermediate) mutable accumulation type (container) * @param <R> (output) result type */  public interface Collector<T, A, R> { Supplier<A> supplier(); // create a container BiConsumer<A, T> accumulator(); // add to the container BinaryOperator<A> combiner(); // combine two containers Function<A, R> finisher(); // get the final result from the container Set<Characteristics> characteristics(); // irrelevant here  } 

上面的合同本质上是功能性的,这非常好! 这使我们可以使用任意累积类型( A )创建Collector ,例如:

  • AStringBuilderCollectors.joining
  • AOptionalBoxCollectors.reducing
  • Along[]Collectors.averagingLong

提案

在我提供任何理由之前,我将提出建议,因为它很简短。 该提议的完整源代码可以在GitHub上找到 。

累积接口

我建议将以下称为Accumulative (名称待讨论)的接口添加到JDK:

 public interface Accumulative<T, A extends Accumulative<T, A, R>, R> { void accumulate(T t); // target for Collector.accumulator() A combine(A other); // target for Collector.combiner() R finish(); // target for Collector.finisher()  } 

Collector相反,此接口本质上是面向对象的 ,实现该接口的类必须表示某种可变状态

过载收集器

具有Accumulative ,我们可以添加以下Collector.of重载:

 public static <T, A extends Accumulative<T, A, R>, R> Collector<T, ?, R> of( Supplier<A> supplier, Collector.Characteristics... characteristics) { return Collector.of(supplier, A::accumulate, A::combine, A::finish, characteristics);  } 

普通开发者故事

在本部分中,我将展示该建议会对普通开发人员产生怎样的影响,而一般开发人员了解 Collector API的基础知识 。 如果您精通此API,请在继续阅读之前尽力想象您不知道。

让我们重用我最近的文章中的示例(进一步简化)。 假设我们有一个Stream

 interface IssueWiseText { int issueLength(); int textLength();  } 

并且我们需要计算问题覆盖率

总发行时长
─────────────
总文字长度

此要求转换为以下签名:

 Collector<IssueWiseText, ?, Double> toIssueCoverage(); 

一般的开发人员可能会决定使用自定义累积类型A来解决此问题(不过其他解决方案也是可能的 )。 假设开发人员将其命名为CoverageContainer这样:

  • TIssueWiseText
  • ACoverageContainer
  • RDouble

在下面,我将展示这样的开发人员如何实现CoverageContainer结构

无累积结构

注意 :本节很长,目的是说明该过程对于没有使用Collector的开发人员可能有多复杂 如果您已经意识到这一点则可以跳过它

如果没有Accumulative ,则开发人员将查看Collector.of ,并看到四个主要参数:

  1. Supplier<A> supplier
  2. BiConsumer<A, T> accumulator
  3. BinaryOperator<A> combiner
  4. Function<A, R> finisher

要处理Supplier <A> supplier ,开发人员应:

  1. Supplier<A>中用心理替代A获得Supplier<CoverageContainer>
  2. 在精神上将签名解析为CoverageContainer get ()
  3. 回想一下JavaDoc for Collector.supplier()
  4. 第四种调用方法的引用 ( 对构造函数的引用
  5. 意识到supplier = CoverageContainer::new

要处理BiConsumer <A, T> accumulator ,开发人员应:

  1. BiConsumer<CoverageContainer, IssueWiseText>
  2. void accept (CoverageContainer a, IssueWiseText t)
  3. 在精神上将签名转换为一种实例方法
    void accumulate(IssueWiseText t)
  4. 第三种调用方法的引用 ( 引用特定类型的任意对象的实例方法
  5. 意识到accumulator = CoverageContainer::accumulate

处理BinaryOperator <A> combiner

  1. BinaryOperator<CoverageContainer>
  2. CoverageContainer apply (CoverageContainer a, CoverageContainer b)
  3. CoverageContainer combine(CoverageContainer other)
  4. combiner = CoverageContainer::combine

要处理Function <A, R> finisher

  1. Function<CoverageContainer, Double>
  2. Double apply (CoverageContainer a)
  3. double issueCoverage()
  4. finisher = CoverageContainer::issueCoverage

这个漫长的过程导致:

 class CoverageContainer { void accumulate(IssueWiseText t) { } CoverageContainer combine(CoverageContainer other) { } double issueCoverage() { }  } 

开发人员可以定义toIssueCoverage() (必须以正确的顺序提供参数):

 Collector<IssueWiseText, ?, Double> toIssueCoverage() { return Collector.of( CoverageContainer:: new , CoverageContainer::accumulate, CoverageContainer::combine, CoverageContainer::finish );  } 

累积结构

现在, 使用 Accumulative ,开发人员将查看新的Collector.of重载,并且将仅看到一个主要参数:

  1. Supplier<A> supplier

和一个有界类型参数 :

  • A extends Accumulative<T, A, R>

因此,开发人员将自然而然地开始- 实施 Accumulative<T, A, R>第一次和最后一次解析TAR

 class CoverageContainer implements Accumulative<IssueWiseText, CoverageContainer, Double> {  } 

此时,一个不错的IDE会抱怨该类必须实现所有抽象方法。 而且,这是最美丽的部分 ,它将提供快速修复。 在IntelliJ中,您单击“ Alt + Enter”→“实施方法”,然后…就完成了!

 class CoverageContainer implements Accumulative<IssueWiseText, CoverageContainer, Double> { @Override public void accumulate(IssueWiseText issueWiseText) {     } @Override public CoverageContainer combine(CoverageContainer other) { return null ; } @Override public Double finish() { return null ; }  } 

因此,您不必摆弄类型,手动编写任何内容或命名任何内容!

哦,是的-您仍然需要定义toIssueCoverage() ,但是现在很简单:

 Collector<IssueWiseText, ?, Double> toIssueCoverage() { return Collector.of(CoverageContainer:: new );  } 

那不是很好吗?

实作

这里的实现无关紧要,因为这两种情况( diff )几乎相同。

基本原理

程序太复杂

我希望我已经演示了如何定义自定义Collector是一个挑战。 我必须说,即使我总是不愿意定义一个。 但是,我也感觉到-有了Accumulative ,这种勉强就会消失,因为该过程将缩小为两个步骤:

  1. 实现Accumulative<T, A, R>
  2. 调用Collector.of(YourContainer::new)

推动实施

JetBrains创造了“ 发展动力 ”,我想将其转变为“实施动力”。

由于Collector是一个简单的功能的设备中,这通常是没有意义的(据我可以告诉)来实现它(也有例外 )。 但是,通过Google搜索“实施收集器”可以看到(约5000个结果)人们正在这样做。

这很自然,因为要在Java中创建“自定义” TYPE ,通常会扩展/实现TYPE 。 实际上,即使是经验丰富的开发人员(例如Java冠军Tomasz Nurkiewicz )也可以做到这一点。

总结起来,人们感到有实现动力 ,但在这种情况下,JDK没有为他们提供实现的任何东西。 Accumulative可以填补这一空白……

相关例子

最后,我搜索了一些示例,这些示例可以轻松实现Accumulative

在OpenJDK(尽管这不是目标位置)中,我发现了两个:

  1. Collectors.reducing ( diff )
  2. Collectors.teeing ( diff )

对堆栈溢出,虽然,我发现大量的: 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47 , 48 , 49 , 50 , 51 , 52 , 53 。

我还发现了一些基于数组的示例,可以将其重构Accumulative以获得更好的可读性: a , b , c 。

命名

Accumulative不是最好的名字,主要是因为它是一个形容词 。 但是,我选择它是因为:

  • 我希望名称以A开头(如<T, A, R> ),
  • 我最好的候选人( Accumulator )已经被BiConsumer<A, T> accumulator()
  • AccumulativeContainer似乎太长。

在OpenJDK中, A称为:

  • 可变结果容器
  • 累积类型
  • 容器

提示以下替代方法:

  • AccumulatingBox
  • AccumulationState
  • Collector.Container
  • MutableResultContainer

当然,如果这个想法被接受,这个名字将通过“传统”的名字

摘要

在本文中,我建议向JDK添加Accumulative接口和新的Collector.of重载。 有了它们,开发人员将不再费劲地创建自定义Collector 。 取而代之的是,它只是成为“执行合同”和“引用构造函数”。

换句话说,该提案旨在降低进入“定制Collector世界的门槛

附录

下面的可选阅读。

解决方案示例:JDK 12+

在JDK 12+中,由于Collectors.teeing ( JDK-8209685 ),我们将toIssueCoverage()定义为组合的Collector

static Collector<IssueWiseText, ?, Double> toIssueCoverage() {return Collectors.teeing(Collectors.summingInt(IssueWiseText::issueLength),Collectors.summingInt(IssueWiseText::textLength),(totalIssueLength, totalTextLength) -> (double) totalIssueLength / totalTextLength);
}

上面的内容很简洁,但是对于Collector API新手来说,可能很难遵循。

示例解决方案:JDK方法

另外, toIssueCoverage()可以定义为:

static Collector<IssueWiseText, ?, Double> toIssueCoverage() {return Collector.of(() -> new int[2],(a, t) -> { a[0] += t.issueLength(); a[1] += t.textLength(); },(a, b) -> { a[0] += b[0]; a[1] += b[1]; return a; },a -> (double) a[0] / a[1]);
}

我称其为“ JDK方式”,因为某些Collector的实现与OpenJDK中的实现类似(例如Collector.averagingInt )。

但是,尽管这样的简洁代码可能适用于OpenJDK,但由于可读性高(这很低,我称之为cryptic ),因此它肯定适合业务逻辑。

翻译自: https://www.javacodegeeks.com/2019/02/accumulative-custom-java-collectors.html

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

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

相关文章

信道接入技术及协议

1. 信道共享方式 在普通的通信系统中&#xff0c;信道共享方式有3种&#xff1a;点对点、点对多点和多点共享。 1.1 点对点 点对点是最简单的信道共享方式。其特点是只有两个节点共享无线信道。在单信道时&#xff0c;两个节点可以通过半双工方式实现共享&#xff0c;在双信…

【渝粤题库】陕西师范大学151101 经济法概论作业 (笔试题型)

《经济法概论》作业 一、单项选择题 1、不可成为经济法律关系客体的是&#xff08; &#xff09; A. 有价证券 B. 无形资产 C. 建筑工程 D.国家保护文物等禁止流通物 2、仲裁实行&#xff08; &#xff09; A.一裁终局制 B.两裁终局制 C.三裁终局制 D.裁终局制 3、下列关于个人…

jdk8 cms g1gc_G1 vs CMS vs平行GC

jdk8 cms g1gc这篇文章是我们一年前进行的实验的跟进&#xff0c;比较了现实环境中不同GC算法的性能。 我们进行了相同的实验&#xff0c;将测试扩展为包含G1垃圾收集器&#xff0c;然后在不同的平台上运行了测试。 今年&#xff0c;我们的测试使用了以下垃圾收集器&#xff1a…

【渝粤题库】陕西师范大学152103 公共行政学

《公共行政学&#xff08;专科&#xff09;》作业 一、单选题 1&#xff0e;“政治与行政二分”最早的提出者是&#xff08; &#xff09;。 A.凯恩斯 B.布坎南 C.韦伯 D.威尔逊 2&#xff0e;新公共管理运动肇始于&#xff08; &#xff09;。 A.英国 B.美国 C.德国 D.新西兰 …

Matlab查看数组大小的命令——size、length、numel和ndims

1 size 功能&#xff1a;主要用来获得矩阵的各个维数的大小&#xff0c;或者指定维数的大小。 语法&#xff1a; d size(X) [m,n] size(X) m size(X,dim) [d1,d2,d3,…,dn] size(X) 其语法应用比较灵活。 2 length 功能&#xff1a;用来获得数组长度&#xff0c;即…

Java的精妙之处,包括基元和变量参数数组

在我最近的博客文章Arrays.hashCode&#xff08;&#xff09;与 DZone联合版本的评论中提出了一个有趣的问题。 Objects.hash&#xff08;&#xff09; “。 该评论的作者建立了一些示例&#xff0c;这些示例与我的博客文章中使用的示例相似&#xff0c;并且显示出与我看到的结…

【渝粤题库】陕西师范大学163201 旅游科学引论作业(专升本)

《旅游科学引论》作业 一、简答题 1、旅游是什么&#xff1f; 2、旅游学的研究对象是什么&#xff1f; 3、旅游能干什么&#xff1f; 4、什么是旅游学&#xff1f; 5、旅游的本质是什么&#xff1f; 6、旅游学的学科性质是什么&#xff1f; 7、旅游学的学科如何构成&#xff1f…

【渝粤题库】陕西师范大学180103市场营销学Ⅰ作业(高起专)

《市场营销学I》作业 一、单项选择题 1、人的需求是无限的&#xff0c;但是有限的&#xff08; &#xff09;限制了人们的大部分欲求。 A&#xff0e;场所 B&#xff0e;商品交换关系 C&#xff0e;人口 D&#xff0e;购买力 2、市场营销的核心是&#xff08; &#xff09;。 …

MATLAB | 解决打开延迟的情况

问题 最近打开matlab&#xff0c;一直没有反应&#xff0c;大概几分钟后&#xff0c;才开始有反应。 网上关于matlab启动出现延迟的方法有很多种解决方法。但都是针对破解版的&#xff0c;而装正版matlab2020b&#xff0c;缺少license文件。对于此&#xff0c;我们尝试用另外一…

【渝粤题库】陕西师范大学200751 《操作系统》作业

《操作系统》作业 一&#xff0e;填空题。 1.加在计算机硬件上的第一层软件为 它是微机以至任何一台计算机必须配置的系统软件。 2.操作系统设计时追求的目标中&#xff0c;其有效性是指 。 3.批(包括多道和单道)处理系统的最大缺点是 &#xff0c;从而使得用户调试程序的周期…

50 个具有挑战性的概率问题 [01/50]:袜子抽屉

一、说明 我最近对与概率有关的问题产生了兴趣。我偶然读到了弗雷德里克莫斯特勒&#xff08;Frederick Mosteller&#xff09;的《概率论中的五十个具有挑战性的问题与解决方案》&#xff08;Fifty Challenge Problems in Probability with Solutions&#xff09;一书。我认为…

matlab中数值的取整、四舍五入、文本输出

一、取整函数 Matlab取整函数有: fix, floor, ceil, round四种&#xff0c;具体使用方法如下&#xff1a; (1) fix 朝零方向取整 如 fix(-1.3)-1 fix(1.3)1; (2) floor 朝负无穷方向取整&#xff08;不超过x 的最大整数.&#xff08;高斯取整&#xff09;&#xff09; …

【渝粤题库】陕西师范大学201341 刑事诉讼法学作业

《刑事诉讼法》作业 一、单项选择题 1&#xff0e;公诉案件中的犯罪嫌疑人有权委托辨护人的时间是下列选项中的哪一个&#xff1f;&#xff08; &#xff09; A 自侦查机关立案之日起 B 自被采取强制措施之日起 C 自案件移送起诉之日起 D 自案件做出起诉决定之日起 2&#xff0…

制作程序化装饰花纹图案_装饰图案

制作程序化装饰花纹图案装饰图案 我不经常使用的一种设计模式是Decorator 。 我不确定为什么这种模式不受欢迎&#xff0c;因为它很方便。 装饰器模式允许以受控方式向对象添加功能。 即使在使用静态类型的语言时&#xff0c;也可以在运行时运行&#xff01; 装饰器模式是子类的…

[渝粤题库]西北工业大学电力系统自动装置

电力系统自动装置 一. 单选题 &#xff08;共21题,共42分&#xff09; 发电机调速系统的失灵区&#xff08; &#xff09;。 &#xff08;2分&#xff09; A.越大越好 B.越小越好 C.要合适同步发电机无功调节特性特性下倾&#xff0c;对应的调差系数&#xff08; &#xff09;…

game,match,competition,contest区别

【1】game&#xff1a; 指决定胜负的比赛&#xff0c;游戏&#xff0c;通常有一定的规则&#xff0c;参加者必须遵守&#xff0c;且多以个人对抗或集体对抗形式根据一定的规则进行的比赛。 【2】match&#xff1a; 多指重要的&#xff0c;参加队数较多的大型体育运动项目比赛&…

[渝粤题库]西北工业大学经济数学(上) (1)

经济数学&#xff08;上&#xff09; 1.&#xff08; &#xff09;. C. 答案:C 2.极限等于&#xff08; &#xff09;. A.0 答案:A 3.已知&#xff0c;当&#xff08; &#xff09;时&#xff0c;为无穷小量. A. 答案:A 4.&#xff08; &#xff09;. C. 答案:C 5.&#xff08…

[渝粤题库]西北工业大学高等数学(上)

高等数学&#xff08;上&#xff09; 当时&#xff0c;与比较是&#xff08; 非等价的同阶无穷小量 &#xff09;. 当时&#xff0c;与等价的无穷小量是&#xff08; &#xff09;. 10、当x→0时&#xff0c;下面无穷小量中与x等价的无穷小量为&#xff08; sin x &#xff09;…

assure, ensure, insure, guarantee的区别

assure, ensure, insure, guarantee都含有一定的"保证"之意 assure 表示向某人保证某事一定会发生(内含有让某人放心之意&#xff0c;以消除疑虑) assure sb. of sth /assure sb. that… He assured us of his ability to solve the problem&#xff0e;他向我们保…

6个您需要了解的日志管理工具(以及如何使用它们)

如果没有正确的工具来汇总和解析日志数据&#xff0c;则几乎不可能找到并了解您正在寻找的信息。 日志有无穷无尽的用途&#xff0c;因为日志本身是无止境的。 应用程序日志&#xff0c;安全日志&#xff0c;BI日志&#xff0c; 林肯日志 &#xff08;好吧&#xff0c;也许不是…