作者:CarpenterLee
https://github.com/CarpenterL...

Java8的Stream API能够极大进步Java程序员的生产力,让程序员写出高效率、洁净、简洁的代码。

那么,Stream API的性能到底如何呢,代码整洁的背地是否意味着性能的损耗呢?本文对Stream API的性能一探到底。

为保障测试后果真实可信,咱们将JVM运行在 -server模式下,测试数据在GB量级,测试机器采纳常见的商用服务器,配置如下:

测试所用代码在这里

https://github.com/CarpenterL...

测试后果汇总

https://github.com/CarpenterL...

测试方法和测试数据

性能测试并不是容易的事,Java性能测试更吃力,因为虚拟机对性能的影响很大,JVM对性能的影响有两方面:

1、GC的影响。GC的行为是Java中很不好管制的一块,为减少确定性,咱们手动指定应用CMS收集器,并应用10GB固定大小的堆内存。个体到JVM参数就是 -XX:+UseConcMarkSweepGC-Xms10G-Xmx10G

2、JIT(Just-In-Time)即时编译技术。即时编译技术会将热点代码在JVM运行的过程中编译成本地代码,测试时咱们会先对程序预热,触发对测试函数的即时编译。相干的JVM参数是 -XX:CompileThreshold=10000

Stream并行执行时用到 ForkJoinPool.commonPool()失去的线程池,为管制并行度咱们应用Linux的 taskset命令指定JVM可用的核数。

测试数据由程序随机生成。为避免一次测试带来的抖动,测试4次求出均匀工夫作为运行工夫。

试验一 根本类型迭代

测试内容:找出整型数组中的最小值。比照for循环内部迭代和Stream API外部迭代性能。

测试程序 IntTest

https://github.com/CarpenterL...

测试后果如下图:

图中展现的是for循环内部迭代耗时为基准的工夫比值。剖析如下:

1、对于根本类型Stream串行迭代的性能开销显著高于内部迭代开销(两倍);

2、Stream并行迭代的性能比串行迭代和内部迭代都好。

并行迭代性能跟可利用的核数无关,上图中的并行迭代应用了全副12个核,为考查应用核数对性能的影响,咱们专门测试了不同核数下的Stream并行迭代成果:

剖析,对于根本类型:

1、应用Stream并行API在单核状况下性能很差,比Stream串行API的性能还差;

2、随着应用核数的减少,Stream并行成果逐步变好,比应用for循环内部迭代的性能还好。

以上两个测试阐明,对于根本类型的简略迭代,Stream串行迭代性能更差,但多核状况下Stream迭代时性能较好。

试验二 对象迭代

再来看对象的迭代成果。

测试内容:找出字符串列表中最小的元素(天然程序),比照for循环内部迭代和Stream API外部迭代性能。

测试程序StringTest

https://github.com/CarpenterL...

对 Stream 不相熟的,能够关注微信公众号:Java技术栈,在后盾回复:Java。

测试后果如下图:

后果剖析如下:

1、对于对象类型Stream串行迭代的性能开销依然高于内部迭代开销(1.5倍),但差距没有根本类型那么大。

2、Stream并行迭代的性能比串行迭代和内部迭代都好。

再来独自考查Stream并行迭代成果:

剖析,对于对象类型:

1、应用Stream并行API在单核状况下性能比for循环内部迭代差;

2、随着应用核数的减少,Stream并行成果逐步变好,多核带来的成果显著。

以上两个测试阐明,对于对象类型的简略迭代,Stream串行迭代性能更差,但多核状况下Stream迭代时性能较好。

试验三 简单对象归约

从试验一、二的后果来看,Stream串行执行的成果都比内部迭代差(很多),是不是阐明Stream真的不行了?先别下结论,咱们再来考查一下更简单的操作。

测试内容:给定订单列表,统计每个用户的总交易额。比照应用内部迭代手动实现和Stream API之间的性能。

咱们将订单简化为 <userName,price,timeStamp>形成的元组,并用 Order对象来示意。测试程序ReductionTest

https://github.com/CarpenterL...

测试后果如下图:

剖析,对于简单的归约操作:

1、Stream API的性能广泛好于内部手动迭代,并行Stream成果更佳;

再来考查并行度对并行成果的影响,测试后果如下:

剖析,对于简单的归约操作:

1、应用Stream并行归约在单核状况下性能比串行归约以及手动归约都要差,简略说就是最差的;

2、随着应用核数的减少,Stream并行成果逐步变好,多核带来的成果显著。

以上两个试验阐明,对于简单的归约操作,Stream串行归约成果好于手动归约,在多核状况下,并行归约成果更佳。咱们有理由置信,对于其余简单的操作,Stream API也能体现出类似的性能体现。

论断

上述三个试验的后果能够总结如下:

1、对于简略操作,比方最简略的遍历,Stream串行API性能显著差于显示迭代,但并行的Stream API可能施展多核个性。

2、对于简单操作,Stream串行API性能能够和手动实现的成果匹敌,在并行执行时Stream API成果远超手动实现。

所以,如果出于性能思考

1、对于简略操作举荐应用内部迭代手动实现

2、对于简单操作,举荐应用Stream API

3、在多核状况下,举荐应用并行Stream API来施展多核优势,

4、单核状况下不倡议应用并行Stream API。

如果出于代码简洁性思考,应用Stream API可能写出更短的代码。即便是从性能方面说,尽可能的应用Stream API也另外一个劣势,那就是只有Java Stream类库做了降级优化,代码不必做任何批改就能享受到降级带来的益处。

近期热文举荐:

1.600+ 道 Java面试题及答案整顿(2021最新版)

2.终于靠开源我的项目弄到 IntelliJ IDEA 激活码了,真香!

3.阿里 Mock 工具正式开源,干掉市面上所有 Mock 工具!

4.Spring Cloud 2020.0.0 正式公布,全新颠覆性版本!

5.《Java开发手册(嵩山版)》最新公布,速速下载!

感觉不错,别忘了顺手点赞+转发哦!