Java8 的 Stream API 的确牛X,但性能究竟如何呢?

JDK8特性(Lambda表达式+StreamAPI简单示例代码) JDK8特性(Lambda表达式+StreamAPI的简单使用示例代码) 立即下载
  • 作者:Carpenter Lee

  • github.com/CarpenterLee/JavaLambdaInternals

Stream Performance

已经对 Stream API 的用法鼓吹够多了,用起简洁直观,但性能到底怎么样呢?会不会有很高的性能损失?本节我们对 Stream API 的性能一探究竟。

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

OSCentOS 6.7 x86_64
CPUIntel Xeon X5675, 12M Cache 3.06 GHz, 6 Cores 12 Threads
内存96GB
JDKjava version 1.8.0_91, Java HotSpot(TM) 64-Bit Server VM

测试方法和测试数据

性能测试并不是容易的事,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,测试结果如下图:

图中展示的是 for 循环外部迭代耗时为基准的时间比值。分析如下:

  1. 对于基本类型 Stream 串行迭代的性能开销明显高于外部迭代开销(两倍);

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

并行迭代性能跟可利用的核数有关,上图中的并行迭代使用了全部 12 个核,为考察使用核数对性能的影响,我们专门测试了不同核数下的 Stream 并行迭代效果:

分析,对于基本类型:

  1. 使用 Stream 并行 API 在单核情况下性能很差,比 Stream 串行 API 的性能还差;

  2. 随着使用核数的增加,Stream 并行效果逐渐变好,比使用 for 循环外部迭代的性能还好。

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

实验二 对象迭代

再来看对象的迭代效果。

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

测试程序 StringTest,测试结果如下图:

结果分析如下:

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

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

再来单独考察 Stream 并行迭代效果:

分析,对于对象类型:

  1. 使用 Stream 并行 API 在单核情况下性能比 for 循环外部迭代差;

  2. 随着使用核数的增加,Stream 并行效果逐渐变好,多核带来的效果明显。

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

实验三 复杂对象归约

从实验一、二的结果来看,Stream 串行执行的效果都比外部迭代差(很多),是不是说明 Stream 真的不行了?先别下结论,我们再来考察一下更复杂的操作。

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

我们将订单简化为 <userName,price,timeStamp>构成的元组,并用 Order对象来表示。测试程序 ReductionTest,测试结果如下图:

分析,对于复杂的归约操作:

  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 类库做了升级优化,代码不用做任何修改就能享受到升级带来的好处。

(完)

【推荐阅读】

Spring Boot 这么火,常用注解和原理都给你整理好了!

超全 MyBatis 动态 SQL 详解!(看完 SQL 爽多了)

从理论到综合实例,终于弄懂了双工通讯协议websocket!

作为开发人员,你不得不懂的Github搜索技巧!

好文!必须点赞

SAP数据导入避坑指南:财务期初上线实操全流程(含常见错误排查) 本文详细解析了SAP财务期初数据导入的全流程,包括数据准备、主数据标准化、余额与未清项导入等关键步骤,并提供了常见错误排查和解决方案。特别强调了过渡科目和存货价值的处理技巧,帮助企业在SAP系统上线时避免数据导入陷阱,确保财务数据的准确性和系统平稳运行。 阅读详情

相关推荐

英飞凌 AURIX Development Studio工程移植到Hightec的方法

1. 软件简介 AURIX™ Development Studio是英飞凌针对AURIX TC2XX/TC3XX系列单片机推出了一款免费的软件,集成了iLLD库,内置Tasking compiler和Tasking Debugger,但这两个模块只能用于非商业用途,可供学习和试用。iLLD库是英飞凌为TC2XX和TC3XX Tricore系列单片机提供的底层驱动库,有完善的使用手册,和较好的移植性。 Hightec是一款可以用来开发Aurix系列单片机的编译器,有免费版,可商用,集成GCC编译器,可用UDE

weixin_42967006的博客 7139

初步了解 java 8 stream 原理

1、为什么使用 Stream for 循环或者 Iterator 循环的不足 如果想要在一次循环迭代中完成多次操作(例如,在一次循环中,进行去重、过滤、元素转换、排序操作),会比较繁琐,甚至需要多次循环才能达到自己的目标。造成的不好的结果,一个是代码比较繁琐,一个是多次循环迭代会有性能损失(局部变量会增加,增加了内存的开支) 如果希望使用并行处理,需要自己编写代码 如果需要进行一些统计操作,需要自己编写相关代码,而这些代码往往又是比较繁杂的 Stream 的优势 一次迭代中支持多种操作 使用 Fork

what are you living for ? 499

旅行青蛙破解汉化教程——蹭个热度

汉化破解版资源(无尽三叶草与点券): https://github.com/wisdombyzf/lxqw/blob/master/lxqw_zf.apk 截图: 破解方法: 工具: 1,APKIDE https://www.pd521.com/thread-818-1-2.html 2,dnspy https://down.52pojie.

github_38838414的博客 3785

Java Stream API 深入解析:高效处理数据的利器

Stream 是 Java 中处理集合的一个新抽象层。与集合不同,Stream 关注的是对数据的运算,而不是数据的存储。Stream API 提供了一种高效的、可读性强的方式来处理数据集。Java Stream API 是处理数据集的强大工具,通过灵活的中间操作和终端操作,可以简化代码、提高效率。如果你觉得这篇文章对你有所帮助,欢迎分享给你的朋友或者在评论区留言讨论!关注我,获取更多Java编程技巧和最新技术分享!

阿里渣渣java研发组-群主 1860

GD32F303调试小记(一)之USART(接收中断、接收空闲中断+DMA、发送DMA)

前言 之前写了GD32F103调试小记(二)之USART(接收中断、接收空闲中断+DMA、发送DMA)一文。这次我们来看看GD32F303的USART是如何配置的,结合这两篇文章,相信大家GD32的USART配置流程会十分熟悉。 DMA 能大大减轻CPU负荷的东西,建议场景合适的情况下,都去用DMA功能。 USART 一种串行通信协议, ...

欢喜6666的博客 3万+

Excel曲线拟合实战:从基础趋势线到高级回归分析

本文系统介绍了Excel曲线拟合的完整工作流,从基础的散点图与趋势线应用,到利用Solver插件进行自定义高级回归分析。文章详细讲解了线性、多项式、指数、对数等六大常用数学模型的适用场景与选择方法,并强调了通过R²值、残差图评估拟合效果、避免过拟合与外推风险的关键步骤,帮助读者掌握从数据探索到预测评估的实战技能。

weixin_29280219的博客 538

Java8强大的新特性 —— “Stream API”

什么是Stream?如何创建?操作链?

Zane Xu的博客 909

模型泛化能力提升:领域自适应与迁移学习

模型泛化能力提升:领域自适应与迁移学习​ ,人工智能,计算机视觉,大模型,AI,在机器学习和深度学习的应用中,模型的泛化能力是一个关键问题。泛化能力指的是模型在新的、未见过的数据上表现良好的能力。然而,实际情况中,训练数据和测试数据往往来自不同的领域,存在分布差异,这会导致模型的泛化能力下降。领域自适应与迁移学习正是为了解决这一问题而发展起来的重要技术。

不踩坑,不知道坑有多深;不总结,踩过的坑白踩。 3万+

解析Java中的Stream API:函数式编程与性能优化

Stream是Java 8引入的一个重要特性,它允许开发者以声明性方式处理数据集合。惰性求值:Stream操作通常是惰性求值的,意味着链式调用的操作不会立即执行,而是直到真正需要结果时才会执行。无副作用:Stream操作通常不修改原始数据结构,它们会返回一个新的Stream或其他类型的结果。并行处理:Stream支持并行处理数据,利用多核处理器提升性能。Java的Stream API不仅是函数式编程的一个重要特性,它极大地提升了数据处理的简洁性和表达力。

byby0325_的博客 2074

【100%通过率】华为OD机试真题 Python 实现【打印机队列】【2022.11 Q4 新题】

有5台打印机打印文件,每台打印机有自己的待打印队列。因为打印的文件内容有轻重缓急之分,所以队列中的文件有1~10不同的代先级,其中数字越大优先级越高。打印机会从自己的待打印队列中选择优先级最高的文件来打印。如果存在两个优先级一样的文件,则选择最早进入队列的那个文件。现在请你来模拟这5台打印机的打印过程。

MISAYAONE的博客 1万+

ARM交叉编译gdbserver并远程在线调试

arm-linux平台。5、生成完整的makefile,新建full_install,执行 ./configure --target=arm-linux-gnueabihf --host=arm-linux-gnueabihf --program-prefix=arm-linux-gnueabihf- CC=arm-linux-gnueabihf-gcc --prefix=/home/geyuxi/Documents/full_install。如果--host和--build不同,是交叉编译;

wangjie36的博客 3169

Java8 的 Stream API 的确牛X,但性能究竟怎么样?

点击上方蓝色字体,选择“标星公众号”优质文章,第一时间送达上一篇:这300G的Java资料是我师傅当年给我的,免费分享给大家(已修复)下一篇:昨天分享资料不小心把百度网盘深处的秘密泄露了...

公众号-老炮说Java 315

YOLO26改进策略【YOLO和Mamba】| 替换骨干 Mamba-YOLO26-T !!! 最新的发文热点

模块是模型中的一个重要组成部分,其主要作用是在模型的初始阶段对输入图像进行处理,方便后续的特征提取和目标检测。以下是对。

Limiiiing的博客 901

Java 8 Stream的性能到底如何?

之前的文章中我们介绍了Java 8中Stream相关的API,我们提到Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。 那么,Stream API的性能到底如何呢,代码整洁的背后是否意味着性能的损耗呢?本文我们对Stream API的性能一探究竟。 为保证测试结果真实可信,我们将JVM运行在-server模式下,测试数据在GB量级,测试机器采用常见...

zhaoxj_2017的博客 1302

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

Java Stream API 学习笔记

Stream API 是 Java 8 引入的强大功能,它为处理数据集合提供了一种新的范式。Stream API 可以简化代码,提高可读性,并充分利用多核处理器来提升性能。

2301_76962889的博客 2147

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

上一篇: 京东二面用JVM参数的这个坑,卡住了90%的人
下一篇: 面试了一个 46 岁程序员,思绪万千
Java思维导图
博客等级 码龄10年 306粉丝 71原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值