java 8 stream reduce详解和误区

简介

Stream API提供了一些预定义的reduce操作,比如count(), max(), min(), sum()等。如果我们需要自己写reduce的逻辑,则可以使用reduce方法。

本文将会详细分析一下reduce方法的使用,并给出具体的例子。

reduce详解

Stream类中有三种reduce,分别接受1个参数,2个参数,和3个参数,首先来看一个参数的情况:

Optional<T> reduce(BinaryOperator<T> accumulator);

该方法接受一个BinaryOperator参数,BinaryOperator是一个@FunctionalInterface,需要实现方法:

R apply(T t, U u);

accumulator告诉reduce方法怎么去累计stream中的数据。

举个例子:

List<Integer> intList = Arrays.asList(1,2,3);
Optional<Integer> result1=intList.stream().reduce(Integer::sum);
log.info("{}",result1);

上面的例子输出结果:

com.flydean.ReduceUsage - Optional[6]

一个参数的例子很简单。这里不再多说。

接下来我们再看一下两个参数的例子:

T reduce(T identity, BinaryOperator<T> accumulator);

这个方法接收两个参数:identity和accumulator。多出了一个参数identity。

也许在有些文章里面有人告诉你identity是reduce的初始化值,可以随便指定,如下所示:

Integer result2=intList.stream().reduce(100, Integer::sum);
log.info("{}",result2);

上面的例子,我们计算的值是106。

如果我们将stream改成parallelStream:

Integer result3=intList.parallelStream().reduce(100, Integer::sum);
log.info("{}",result3);

得出的结果就是306。

为什么是306呢?因为在并行计算的时候,每个线程的初始累加值都是100,最后3个线程加出来的结果就是306。

并行计算和非并行计算的结果居然不一样,这肯定不是JDK的问题,我们再看一下JDK中对identity的说明:

identity必须是accumulator函数的一个identity,也就是说必须满足:对于所有的t,都必须满足 accumulator.apply(identity, t) == t

所以这里我们传入100是不对的,因为sum(100+1)!= 1。

这里sum方法的identity只能是0。

如果我们用0作为identity,则stream和parallelStream计算出的结果是一样的。这就是identity的真正意图。

下面再看一下三个参数的方法:

<U> U reduce(U identity,
BiFunction<U, ? super T, U> accumulator,
BinaryOperator<U> combiner);

和前面的方法不同的是,多了一个combiner,这个combiner用来合并多线程计算的结果。

同样的,identity需要满足combiner.apply(u, accumulator.apply(identity, t)) == accumulator.apply(u, t)

大家可能注意到了为什么accumulator的类型是BiFunction而combiner的类型是BinaryOperator?

public interface BinaryOperator<T> extends BiFunction<T,T,T>

BinaryOperator是BiFunction的子接口。BiFunction中定义了要实现的apply方法。

其实reduce底层方法的实现只用到了apply方法,并没有用到接口中其他的方法,所以我猜测这里的不同只是为了简单的区分。

总结

虽然reduce是一个很常用的方法,但是大家一定要遵循identity的规范,并不是所有的identity都是合适的。

本文的例子https://github.com/ddean2009/learn-java-streams/tree/master/stream-reduce

欢迎关注我的公众号:程序那些事,更多精彩等着您!

更多内容请访问 www.flydean.com

java 8 stream reduce详解和误区的更多相关文章

  1. Java 8 Stream API详解--转

    原文地址:http://blog.csdn.net/chszs/article/details/47038607 Java 8 Stream API详解 一.Stream API介绍 Java8引入了 ...

  2. Java 8 Stream API 详解

    Java 8 中的 Stream 是对集合(Collection)对象功能的增强,它专注于对集合对象进行各种非常便利.高效的聚合操作(aggregate operation),或者大批量数据操作 (b ...

  3. Java8的Stream语法详解(转载)

    1. Stream初体验 我们先来看看Java里面是怎么定义Stream的: A sequence of elements supporting sequential and parallel agg ...

  4. Java8初体验(二)Stream语法详解(转)

    本文转自http://ifeve.com/stream/ Java8初体验(二)Stream语法详解 感谢同事[天锦]的投稿.投稿请联系 tengfei@ifeve.com上篇文章Java8初体验(一 ...

  5. Java8初体验(二)Stream语法详解---符合人的思维模式,数据源--》stream-->干什么事(具体怎么做,就交给Stream)--》聚合

    Function.identity()是什么? // 将Stream转换成容器或Map Stream<String> stream = Stream.of("I", & ...

  6. Storm 第三章 Storm编程案例及Stream Grouping详解

    1 功能说明 设计一个topology,来实现对文档里面的单词出现的频率进行统计.整个topology分为三个部分: SentenceSpout:数据源,在已知的英文句子中,随机发送一条句子出去. S ...

  7. Java 8 Lambda 表达式详解

    一.Java 8 Lambda 表达式了解 参考:Java 8 Lambda 表达式 | 菜鸟教程 1.1 介绍: Lambda 表达式,也可称为闭包,是推动 Java 8 发布的最重要新特性. La ...

  8. java反射机制深入详解

    java反射机制深入详解  转自:http://www.cnblogs.com/hxsyl/archive/2013/03/23/2977593.html 一.概念 反射就是把Java的各种成分映射成 ...

  9. 国际化,java.util.ResourceBundle使用详解

    java.util.ResourceBundle使用详解   一.认识国际化资源文件   这个类提供软件国际化的捷径.通过此类,可以使您所编写的程序可以:          轻松地本地化或翻译成不同的 ...

随机推荐

  1. python学习第四节 迭代器 生成器

    1:什么是迭代 可以直接作用于for循环的对象统称为可迭代对象(Iterable). 可以被next()函数调用并不断返回下一个值的对象称为迭代器(Iterator). 所有的Iterable均可以通 ...

  2. 1041 Be Unique (20分)(水)

    Being unique is so important to people on Mars that even their lottery is designed in a unique way. ...

  3. web自动化浏览器chrome和驱动chromedriver

    1.web自动化下载浏览器和对应的浏览器驱动,以谷歌浏览器为例 电脑上安装谷歌浏览器,查看谷歌浏览器的版本,输入chrome://settings/help 2.chromedriver国内镜像地址h ...

  4. TC1.6SourceCode java课程表

    /** * @version 2.0 * @author sharks */ /** * Instruction * this version will use IO * apply file to ...

  5. 【物理】AABB物理碰撞检测

    什么是AABB? AABB,指轴对齐包围盒(Axis-aligned bounding boxes).在3D空间中,AABB是一个长方体,在2D空间中是一个长方形.特征是面法线皆平行于坐标轴,即当物体 ...

  6. Linux网络安全篇,进入SELinux的世界(二)

    一.简单的网页制作 1.启动httpd服务 /etc/init.d/httpd start 2.编写首页网页文件 echo "hello,this is my first webPage&q ...

  7. jpa是什么,和hibernate 有什么关系

    JPA通过JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中.JPA 的目标之一是制定一个可以由很多供应商实现的API,并且开发人员可以编码来实现该API,而不 ...

  8. Apache与PHP的配置

    Listen 表示端口号 ServerName 表示域名 <Directory 路径> 表示默认开放的路径 <IfModule dir_module> 表示默认显示的文件名 & ...

  9. 2019-08-02【机器学习】有监督学习之分类 SVC算法 实例(上证指数跌涨预测)

    样本: 代码:有几处与教程不同,自行修改 import pandas as pd import numpy as np from sklearn import svm from sklearn imp ...

  10. 解决Jquery中click里面包含click事件,出现重复执行的问题

    出现问题的代码: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.o ...