Java8 Stream性能如何及评测工具推荐

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

本文链接:https://blog.csdn.net/wo541075754/article/details/102499232

作为技术人员,学习新知识是基本功课。有些知识是不得不学,有些知识是学了之后如虎添翼,Java8的Stream就是兼具两者的知识。不学看不懂,学了写起代码来如虎添翼。

在上篇《Java8 Stream新特性详解及实战》中我们介绍了Java8 Stream的基本使用方法,尝试一下是不是感觉很爽?当只用一行代码就搞定最终结果时,是不是再也不想用for循环一遍遍去迭代了。

同时,你是否又看到类似《Java8 Lambda表达式和流操作如何让你的代码变慢5倍》这样的文章,那么今天就带大家通过编写测试程序来一探究竟,看看Stream的性能到底如何。同时,带大家认识一个非常不错的性能测试工具junitperf。

测试环境

先同步一下测试环境及工具信息:

  • JDK版本:1.8.0_151。
  • 电脑配置:MacBook Pro i7,16G内存。
  • Java测试工具:junitperf及Junit。
  • IDE:intellij IDEA。

在测试的过程中电脑中还开了其他很多应用,但基本上都没进行操作。

实验一:基本类型迭代

基本测试方案,先初始化一个int数组,5亿个随机数。然后从这个数组中找到最小的一个数。

采用三个单元测试方法来对照参考:

  • testIntFor:测试for循环执行时间;
  • testIntStream:测试串行Stream执行时间;
  • testIntParallelStream:测试并行Stream执行时间;

测试程序相关代码:

public class StreamTest {

	public static int[] arr;

	@BeforeAll
	public static void init() {
		arr = new int[500000000];
		randomInt(arr);
	}

	@JunitPerfConfig(duration = 10000, warmUp = 1000, reporter = {HtmlReporter.class})
	public void testIntFor() {
		minIntFor(arr);
	}

	@JunitPerfConfig(duration = 10000, warmUp = 1000, reporter = {HtmlReporter.class})
	public void testIntParallelStream() {
		minIntParallelStream(arr);
	}

	@JunitPerfConfig(duration = 10000, warmUp = 1000, reporter = {HtmlReporter.class})
	public void testIntStream() {
		minIntStream(arr);
	}

	private int minIntStream(int[] arr) {
		return Arrays.stream(arr).min().getAsInt();
	}

	private int minIntParallelStream(int[] arr) {
		return Arrays.stream(arr).parallel().min().getAsInt();
	}

	private int minIntFor(int[] arr) {
		int min = Integer.MAX_VALUE;
		for (int anArr : arr) {
			if (anArr < min) {
				min = anArr;
			}
		}
		return min;
	}

	private static void randomInt(int[] arr) {
		Random r = new Random();
		for (int i = 0; i < arr.length; i  ) {
			arr[i] = r.nextInt();
		}
	}
}

基本操作流程:通过@BeforeAll注解的init方法对数组进行随机初始化,然后再统一执行上面三个测试方法。

在单元测试的方法上都有下面的注解:

@JunitPerfConfig(duration = 10000, warmUp = 1000, reporter = {HtmlReporter.class})

该注释为junitperf提供的注解,其中duration为持续执行这段代码的时间,单位毫秒;warmUp预热时间,这里预热1秒;reporter输出报表格式,这里采用HTML展示,可以更直观看到效果。

好上面的一切都准备好了,剩下的就是统一执行单元测试。执行结果如下三个图。

针对基础类型(int)操作,结果分析:

  • 串行Stream的执行的确不如for循环性能高,耗时大概是for循环的2倍。
  • 并行Stream的执行性能要优于for循环,耗时大概是for循环的一半。
  • 这里没有用不同核数的机器测试,但并行Stream随着服务器核数的增加,必然更快。

实验二:对象迭代

生成一个List列表,列表中随机生成10000000个字符串,然后分别通过不同的方式计算获得最小的字符串。

基本操作与实验一相同,不再贴出代码,直接看测试的效果图。

针对对象(String)操作,结果分析:

  • Stream的性能与for循环已经相差不大了,耗时大概是for循环的1.25倍左右。
  • 并行Stream执行的性能要优于for循环,而且比基础类型的优势更高,耗时已经低于for循环的一半。
  • 针对不同服务器核数,Stream效率同样会更加高。

实验三:复杂对象归约

生成一个List列表,列表里面存放着1百万个User对象。每个对象中都包含用户名和用户某次运动的距离,同一用户可在List里包含多条运动记录。现在通过不同的方式来统计用户的总共运动了多远距离。

基本测试思路一致,这里只贴出基于Stream的算法的代码,以便大家了解Stream的复杂对象归约如何使用。

// 串行写法
users.stream().collect(
				Collectors.groupingBy(User::getUserName,
						Collectors.summingDouble(User::getMeters)));
// 并行写法						
users.parallelStream().collect(
				Collectors.groupingBy(User::getUserName,
						Collectors.summingDouble(User::getMeters)));

下面看测试结果的数据:

复杂对象归约操作,结果分析:

  • 基于Stream的操作明显都高于for循环的效率,而且并行的效果更加明显。
  • 同样,随着服务器核数的增加,并行Stream的效率会更高。

最后推荐一下这款用起来还不错的Java性能测试工具,GitHub地址:https://github.com/houbb/junitperf。 上面有详细的使用说明。唯一缺少的就是数据预初始化的示例,而本篇文章的示例中已经补上了这部分缺失。

小结

通过上面的几组实验对比,我们可以看到如下结论:

  • 针对简单的操作,比如基础类型的遍历,使用for循环性能要明显高于串行Stream操作。但Stream的并行操作随着服务器的核数增加,会优于for循环。
  • 针对复杂操作,串行Stream性能与for循环不差上下,但并行Stream的性能已经是无法匹敌了。
  • 特别是针对一个集合进行多层过滤并归约操作,无论从写法上或性能上都要明显优于for循环。

用一句话来说就是:简单操作for循环即可,复杂操作首推Stream。

现在的Stream书写简单,性能不错,如果未来JDK针对其进行优化,便同时享受了便捷和性能,何乐而不为呢。

原文链接《Java8 Stream性能如何及评测工具推荐

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Java小白成长之路

第8次文章:其他流

使用方法:read(byte[] b,int off,int len) +close()

8530
来自专栏京程一灯

JavaScript 的 Map 指南[每日前端夜话0xC7]

在JavaScript中,Map 是存储键/值对的对象。Map 类似于一般 JavaScript 对象【https://developer.mozilla.or...

9630
来自专栏Java小白成长之路

第17次文章:初探JVM

JVM把class文件加载到内存,并对数据进行校验、解析和初始化,最终形成JVM可以直接使用的java类型的过程。

5830
来自专栏Java小白成长之路

第13次文章:网络编程——httpserver服务器的搭建(中)

这周的代码出了点问题,目前还没有调试完全,就先不把所有代码都粘贴上来了。下周默默的去调代码了!

10830
来自专栏Java小白成长之路

第6次文章:利用IO流,对文件和文件夹进行拷贝操作

最近两周在家,学习效率大打折扣,所以这两周的学习总结不是那么丰富,有点简单,希望各位小伙伴儿多多包涵啊

10250
来自专栏Java小白成长之路

第7次文章:IO流中的重点流

这周的内容是对前面已经学过的一些重要IO流进行一个框架的总结,没有放相关的代码。这几个流的用法都比较简单,正在学Java的小伙伴儿,学到此处的时候,一看就懂!

5310
来自专栏Java小白成长之路

第16次文章:Java字节码

在上一期讲解java的动态性的时候,我们主要提到了java中的反射机制,可以在java代码运行的时候,改变类的结构,属性等信息,而这一节我们通过另一种实现方式来...

12260
来自专栏Java架构沉思录

基础面试,为什么面试官总喜欢问String?

关于 Java String,这是面试的基础,但是还有很多童鞋不能说清楚,所以本文将简单而又透彻的说明一下那个让你迷惑的 String

11220
来自专栏Java小白成长之路

第15次文章:反射+动态编译+脚本引擎

在前面的文章中,我们简单的介绍过一点反射的内容,没有深入,这次的反射内容会比上一次更加深刻一点!

10740
来自专栏老九学堂

全世界程序员都会的编程神器与主流企业工具

老九学堂被老九军们称为“全国最大同性程序员交友平台”,而有一个网站被称为“全世界最大同性程序员交友网站”,那就是Github。

11730

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励