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. java初学复习

    作为学Java的小白,忽然想看一看自己学了些什么东西,话不多说,(这都是新手弄的总结)让我们看一看: 1.我们要先了解Java技术 Java SE:标准版java技术的基础和核心 Java EE:企业 ...

  2. python学习笔记--字符串格式化

    字符串和常量 print(r'hello\py\thon') r 代表后面字符不进行转义,原样输出; 表示常量,命名时变量名字大写代表常量.NAME = 'liulixue'; 字符串表示:' ', ...

  3. 七、【Docker笔记】Docker中网络基础配置

    一个系统一般都包含多个服务组件,这些大量的服务组件不可能放在同一个容器中,这就需要多个容器之间可以互相通信.Docker提供了两种方式来实现网络服务:映射容器端口到宿主主机.容器互联机制. 一.端口映 ...

  4. php连接数据库,php连接mysql并查询的几种方式,PHP PDO连接以及预处理

    PHP连接数据库 面向过程 $config = [ 'host'=>'127.0.0.1', //数据库地址 'name'=>'test', //库名 'user'=>'root', ...

  5. scrapy中使用selenium来爬取页面

    scrapy中使用selenium来爬取页面 from selenium import webdriver from scrapy.http.response.html import HtmlResp ...

  6. 【Web】阿里icon图标webpack插件(webpack-qc-iconfont-plugin)详解

    webpack-qc-iconfont-plugin webpack-qc-iconfont-plugin是一个webpack插件,可以轻松地帮你将阿里icon的图标项目下载至本地 开发初衷 之前已经 ...

  7. excel中存储的时间的类型是什么

    做了一个excel导入数据的功能,其中需要导入时间,默认到天.在开发过程中发现了一个问题, 导入的数据解析到的时间格式是 02-03-19,发现年份前面的两位数丢失了.这当然是导入数据 的解析包的问题 ...

  8. readelf命令

    //查看文件头信息 readelf -h [file] //查看文件依赖的动态库 readelf -d [file] //查看文件中的符号 readelf -s [file]

  9. 通过Java HTTP连接将网络图片下载到本地

    通过Java HTTP连接将网络图片下载到本地   只知道浏览器使用的是HTTP协议,那么如何将网络资源使用JavaHTTP下载下来呢! 这只是一个非常简单的小示例,只是不想每次碰到关于此方面的内容忘 ...

  10. 今日写一篇散文 Textview settext 方法不能放入 int 参数 不然报错!

    Textview settext 方法不能放入 int 参数 不然报错!