java8 reduce的用法_Java 8系列之Stream中万能的reduce用法说明

java8 reduce的用法_Java 8系列之Stream中万能的reduce用法说明reduce操作可以实现从Stream中生成一个值,其生成的值不是随意的,而是根据指定的计算模型。比如,之前提到count、min和max方法,因为常用而被纳入标准库中。事实上,这些方法都是reduce操作。reduce方法有三个override的方法:Optionalreduce(BinaryOperatoraccumulator);Treduce(Tidentity,BinaryO…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全家桶1年46,售后保障稳定

reduce 操作可以实现从Stream中生成一个值,其生成的值不是随意的,而是根据指定的计算模型。比如,之前提到count、min和max方法,因为常用而被纳入标准库中。事实上,这些方法都是reduce操作。

reduce方法有三个override的方法:

Optional reduce(BinaryOperator accumulator);

T reduce(T identity, BinaryOperator accumulator);

U reduce(U identity,BiFunction accumulator,BinaryOperator combiner);

我们先看第一个变形,其接受一个函数接口BinaryOperator,而这个接口又继承于BiFunction.在BinaryOperator接口中,又定义了两个静态方法minBy和maxBy。这里我们先不管这两个静态方法,先了解reduce的操作。

@FunctionalInterface

public interface BinaryOperator extends BiFunction {

public static BinaryOperator minBy(Comparator super T> comparator) {

Objects.requireNonNull(comparator);

return (a, b) -> comparator.compare(a, b) <= 0 ? a : b;

}

public static BinaryOperator maxBy(Comparator super T> comparator) {

Objects.requireNonNull(comparator);

return (a, b) -> comparator.compare(a, b) >= 0 ? a : b;

}

}

在使用时,我们可以使用Lambada表达式来表示

BinaryOperator接口,可以看到reduce方法接受一个函数,这个函数有两个参数,第一个参数是上次函数执行的返回值(也称为中间结果),第二个参数是stream中的元素,这个函数把这两个值相加,得到的和会被赋值给下次执行这个函数的第一个参数。要注意的是:第一次执行的时候第一个参数的值是Stream的第一个元素,第二个参数是Stream的第二个元素。这个方法返回值类型是Optional,

Optional accResult = Stream.of(1, 2, 3, 4)

.reduce((acc, item) -> {

System.out.println(“acc : ” + acc);

acc += item;

System.out.println(“item: ” + item);

System.out.println(“acc+ : ” + acc);

System.out.println(“——–“);

return acc;

});

System.out.println(“accResult: ” + accResult.get());

System.out.println(“——–“);

// 结果打印

——–

acc : 1

item: 2

acc+ : 3

——–

acc : 3

item: 3

acc+ : 6

——–

acc : 6

item: 4

acc+ : 10

——–

accResult: 10

——–

6814e37504bb7716845606dccb8d6b8c.png

下面来看第二个变形,与第一种变形相同的是都会接受一个BinaryOperator函数接口,不同的是其会接受一个identity参数,用来指定Stream循环的初始值。如果Stream为空,就直接返回该值。另一方面,该方法不会返回Optional,因为该方法不会出现null。

int accResult = Stream.of(1, 2, 3, 4)

.reduce(0, (acc, item) -> {

System.out.println(“acc : ” + acc);

acc += item;

System.out.println(“item: ” + item);

System.out.println(“acc+ : ” + acc);

System.out.println(“——–“);

return acc;

});

System.out.println(“accResult: ” + accResult);

System.out.println(“——–“);

// 结果打印

acc : 0

item: 1

acc+ : 1

——–

acc : 1

item: 2

acc+ : 3

——–

acc : 3

item: 3

acc+ : 6

——–

acc : 6

item: 4

acc+ : 10

——–

accResult: 10

——–

从打印结果可以看出,reduce前两种变形,因为接受参数不同,其执行的操作也有相应变化:

变形1,未定义初始值,从而第一次执行的时候第一个参数的值是Stream的第一个元素,第二个参数是Stream的第二个元素

变形2,定义了初始值,从而第一次执行的时候第一个参数的值是初始值,第二个参数是Stream的第一个元素

对于第三种变形,我们先看各个参数的含义,第一个参数返回实例u,传递你要返回的U类型对象的初始化实例u,第二个参数累加器accumulator,可以使用二元?表达式(即二元lambda表达式),声明你在u上累加你的数据来源t的逻辑,例如(u,t)->u.sum(t),此时lambda表达式的行参列表是返回实例u和遍历的集合元素t,函数体是在u上累加t,第三个参数组合器combiner,同样是二元?表达式,(u,t)->u。

在官方文档上有这么一段介绍,

U result = identity;

for (T element : this stream)

result = accumulator.apply(result, element)

return result;

but is not constrained to execute sequentially.

The identity value must be an identity for the combiner function. This means that for all u, combiner(identity, u) is equal to u. Additionally, the combiner function must be compatible with the accumulator function; for all u and t, the following must hold:

combiner.apply(u, accumulator.apply(identity, t)) == accumulator.apply(u, t)

因为reduce的变形的第一个参数类型是实际返回实例的数据类型,同时其为一个泛型也就是意味着该变形的可以返回任意类型的数据。从上面文档介绍的字面意思解读是第三个参数函数用来组合两个值,而这两个值必须与第二个函数参数相兼容,也就是说它们所得的结果是一样的。看到这里肯定有迷惑的地方,第三个参数到底是用来干嘛的?我们先看一段代码,为了便于了解其中的缘由,并没有使用Lambda表达式,

ArrayList accResult_ = Stream.of(1, 2, 3, 4)

.reduce(new ArrayList(),

new BiFunction, Integer, ArrayList>() {

@Override

public ArrayList apply(ArrayList acc, Integer item) {

acc.add(item);

System.out.println(“item: ” + item);

System.out.println(“acc+ : ” + acc);

System.out.println(“BiFunction”);

return acc;

}

}, new BinaryOperator>() {

@Override

public ArrayList apply(ArrayList acc, ArrayList item) {

System.out.println(“BinaryOperator”);

acc.addAll(item);

System.out.println(“item: ” + item);

System.out.println(“acc+ : ” + acc);

System.out.println(“——–“);

return acc;

}

});

System.out.println(“accResult_: ” + accResult_);

// 结果打印

item: 1

acc+ : [1]

BiFunction

item: 2

acc+ : [1, 2]

BiFunction

item: 3

acc+ : [1, 2, 3]

BiFunction

item: 4

acc+ : [1, 2, 3, 4]

BiFunction

accResult_: [1, 2, 3, 4]

accResult_: 10

首先示例代码中,传递给第一个参数是ArrayList,在第二个函数参数中打印了“BiFunction”,而在第三个参数接口中打印了函数接口中打印了”BinaryOperator“.可是,看打印结果,只是打印了“BiFunction”,而没有打印”BinaryOperator“,说明第三个函数参数病没有执行。这里我们知道了该变形可以返回任意类型的数据。

对于第三个函数参数,为什么没有执行,刚开始的时候也是没有看懂到底是啥意思呢,而且其参数必须为返回的数据类型?看了好几遍文档也是一头雾水。

在 java8 reduce方法中的第三个参数combiner有什么作用?

3466d3c0aa24b4699d0274da478e063f.png

acd0a9d5c3be6451a962b17c71401ced.png

这里找到了答案,Stream是支持并发操作的,为了避免竞争,对于reduce线程都会有独立的result,combiner的作用在于合并每个线程的result得到最终结果。

这也说明了了第三个函数参数的数据类型必须为返回数据类型了。

需要注意的是,因为第三个参数用来处理并发操作,如何处理数据的重复性,应多做考虑,否则会出现重复数据!

以上这篇Java 8系列之Stream中万能的reduce用法说明就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持脚本之家。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/230745.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(2)
blank

相关推荐

  • RabbitVCS无法启动,右键失效解决方案

    RabbitVCS无法启动,右键失效解决方案本来用着好好的RabbitVCS,突然间就无法使用了;重新安装也无效,一旦重启就会出现如下错误:原因是RabbitVCS依赖python2.7,但是我的系统默认的python版本,已经改为python3.5了,所以才导致了这个错误,只要把python的版本改回python2.7就可以解决这个问题了:把python2.7设置为更高的权限即可。如下,再启动就OK…

  • 一只救助犬的最后遗言

    一只救助犬的最后遗言这是刚在雅虎上看到的一篇文章,内容讲述一只日本救助犬的真实而动人的故事,阅后不得不让人感叹人与动物之间的感情和谐与真挚。实话说,其令我这个大男人哽咽难语。想想现今,在这个人与人之间充满了不信任,在这

  • 全错位排列组合公式_无顺序排列组合公式

    全错位排列组合公式_无顺序排列组合公式不容易系列之一ProblemDescription大家常常感慨,要做好一件事情真的不容易,确实,失败比成功容易多了!做好“一件”事情尚且不易,若想永远成功而总从不失败,那更是难上加难了,就像花钱总是

  • 思科交换机-常用命令及配置[通俗易懂]

    switch>用户模式1:进入特权模式enableswitch>enableswitch# 2:进入全局配置模式configureterminalswitch>enableswitch#configureterminalswitch(conf)# 3:交换机命名hostnamename以cisco001为例switch>enable

  • java多线程总结

    进程:是一个正在执行的程序每个进程都有一个执行顺序,该顺序是一个执行路径或叫一个控制单元,线程:就是进程中的一个独立的控制单元。线程在控制着进程的执行一个进程中可以有多个线程,但是一个线程只

    2021年12月23日
  • java函数式编程实例(函数式编程实例)

    描述:一元运算,接受一个T类型参数,输出一个与入参类型一样的值源码:publicinterfaceUnaryOperatorextendsFunction{/***Returnsaunaryoperatorthatalwaysreturnsitsinputargument.**@paramth

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号