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

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

作为技术人员,学习新知识是基本功课。有些知识是不得不学,有些知识是学了之后如虎添翼,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})

1

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


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


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


串行Stream的执行的确不如for循环性能高,耗时大概是for循环的2倍。

并行Stream的执行性能要优于for循环,耗时大概是for循环的一半。

这里没有用不同核数的机器测试,但并行Stream随着服务器核数的增加,必然更快。

实验二:对象迭代

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


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


image.png针对对象(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)));

image.pngimage.png复杂对象归约操作,结果分析:


基于Stream的操作明显都高于for循环的效率,而且并行的效果更加明显。

同样,随着服务器核数的增加,并行Stream的效率会更高。

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


小结

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


针对简单的操作,比如基础类型的遍历,使用for循环性能要明显高于串行Stream操作。但Stream的并行操作随着服务器的核数增加,会优于for循环。

针对复杂操作,串行Stream性能与for循环不差上下,但并行Stream的性能已经是无法匹敌了。

特别是针对一个集合进行多层过滤并归约操作,无论从写法上或性能上都要明显优于for循环。

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


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


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


Java8新特性系列

Java8新特性系列相关文章:


《JAVA8新特性时间日期库DATETIME API及示例》

《JAVA8 LAMBDA表达式详解手册及实例》

《JAVA8 STREAM性能如何及评测工具推荐》

《JAVA8 STREAM新特性详解及实战》

《Java8新特性之空指针异常的克星Optional类》



目录
相关文章
|
Java
Java8中stream流处理数据21个小案例(学习使用)
Java8中stream流处理数据21个小案例(学习使用)
152 0
|
SQL 存储 前端开发
【Java技术指南】「Java8技术盲区」在奔向Java13的同时,也让我们仔细研究一下Stream的学习认知!
【Java技术指南】「Java8技术盲区」在奔向Java13的同时,也让我们仔细研究一下Stream的学习认知!
221 0
【Java技术指南】「Java8技术盲区」在奔向Java13的同时,也让我们仔细研究一下Stream的学习认知!
|
Java 程序员 API
Java 8 Stream API学习总结
Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。
1109 0
|
Java API 安全
JAVA8--Stream学习
Stream是什么 怎么使用Stream Stream的建立 Stream中的元素操作 Stream聚合操作 Stream结果处理 Stream分组操作 Stream注意事项 Stream是什么 书上说Stream是对JAVA中对集合处理的抽象,在我看来Stream更像是对java集合的一次扩展,因为Stream中的API都是我们对集合操作中可能遇
1871 0
|
21天前
|
数据采集 存储 弹性计算
高并发Java爬虫的瓶颈分析与动态线程优化方案
高并发Java爬虫的瓶颈分析与动态线程优化方案
Java 数据库 Spring
59 0
|
1月前
|
算法 Java
Java多线程编程:实现线程间数据共享机制
以上就是Java中几种主要处理多线程序列化资源以及协调各自独立运行但需相互配合以完成任务threads 的技术手段与策略。正确应用上述技术将大大增强你程序稳定性与效率同时也降低bug出现率因此深刻理解每项技术背后理论至关重要.
90 16
|
2月前
|
缓存 并行计算 安全
关于Java多线程详解
本文深入讲解Java多线程编程,涵盖基础概念、线程创建与管理、同步机制、并发工具类、线程池、线程安全集合、实战案例及常见问题解决方案,助你掌握高性能并发编程技巧,应对多线程开发中的挑战。
|
2月前
|
数据采集 存储 前端开发
Java爬虫性能优化:多线程抓取JSP动态数据实践
Java爬虫性能优化:多线程抓取JSP动态数据实践
|
3月前
|
Java API 调度
从阻塞到畅通:Java虚拟线程开启并发新纪元
从阻塞到畅通:Java虚拟线程开启并发新纪元
309 83