与长期的实现相比,Java 8 lambda和流的性能如何?

Lambda表达式和流在Java 8中受到了热烈的欢迎。这些是迄今为止很激动人心的功能,很长一段时间以来,它们就已经应用到Java中了。 新的语言功能使我们可以在代码中采用更具功能性的样式,并且在其中玩耍也很有趣。 非常有趣,应该是非法的。 然后我们变得可疑 ,并决定对它们进行测试。

我们已经完成了一个简单的任务,即在ArrayList中找到最大值,并测试了长期的实现与Java 8中可用的新方法的对比。老实说,结果令人惊讶。

Java 8中的命令式与功能式编程

我们喜欢直截了当,所以让我们看一下结果。 对于此基准,我们创建了一个ArrayList,为其中填充了100,000个随机整数,并实现了7种不同的方式来遍历所有值以找到最大值。 这些实现分为两类:具有Java 8中引入的新语言功能的功能样式和具有长期Java方法的命令式样式。

这是每种方法花费的时间:

**记录的最大错误是parallelStream上的0.042,完整的结果输出可在该文章的底部找到

外卖

  1. 哎呀! 使用Java 8提供的任何新方法来实现解决方案,都会使性能下降5倍左右。 有时,使用带有迭代器的简单循环比将lambda和流混入混合要好。 即使这意味着编写更多代码行并跳过那种甜蜜的语法糖。
  2. 使用迭代器或for-each循环是遍历ArrayList的最有效方法。 比具有索引int的传统for循环好两倍。
  3. 在Java 8方法中,使用并行流被证明更有效。 但是要当心, 在某些情况下,它实际上可能会使您减速。
  4. Lambas取代了它们在流和parallelStream实现之间的位置。 这是令人惊讶的,因为它们的实现基于流API。
  5. [编辑]事情并非总是如此:尽管我们想展示在lambda和流中引入错误有多么容易,但我们收到了很多社区反馈,要求为基准代码添加更多优化并删除对它们的装箱/拆箱。整数。 包括优化在内的第二组结果可在本文的底部获得。

等一下,我们到底在这里测试了什么?

让我们快速浏览一下每种方法,从最快到最慢:

命令式

forMaxInteger() –使用简单的for循环和int索引遍历列表:

public int forMaxInteger() {int max = Integer.MIN_VALUE;for (int i = 0; i < size; i++) {max = Integer.max(max, integers.get(i));}return max;
}

iteratorMaxInteger() –使用迭代器遍历列表:

public int iteratorMaxInteger() {int max = Integer.MIN_VALUE;for (Iterator<Integer> it = integers.iterator(); it.hasNext(); ) {max = Integer.max(max, it.next());}return max;
}

forEachLoopMaxInteger() –丢失迭代器,并使用For-Each循环遍历列表(不要误解为Java 8 forEach):

public int forEachLoopMaxInteger() {int max = Integer.MIN_VALUE;for (Integer n : integers) {max = Integer.max(max, n);}return max;
}

功能风格

parallelStreamMaxInteger() –在并行模式下使用Java 8流浏览列表:

public int parallelStreamMaxInteger() {Optional<Integer> max = integers.parallelStream().reduce(Integer::max);return max.get();
}

lambdaMaxInteger() –将lambda表达式与流一起使用。 甜蜜的一线:

public int lambdaMaxInteger() {return integers.stream().reduce(Integer.MIN_VALUE, (a, b) -> Integer.max(a, b));
}

forEachLambdaMaxInteger() –这对于我们的用例来说有点混乱。 新的Java 8 forEach功能可能最令人讨厌的是它只能使用最终变量,因此我们为最终包装器类创建了一些变通方法,该类可以访问我们正在更新的最大值:

public int forEachLambdaMaxInteger() {final Wrapper wrapper = new Wrapper();wrapper.inner = Integer.MIN_VALUE;integers.forEach(i -> helper(i, wrapper));return wrapper.inner.intValue();
}public static class Wrapper {public Integer inner;
}private int helper(int i, Wrapper wrapper) {wrapper.inner = Math.max(i, wrapper.inner);return wrapper.inner;
}

顺便说一句,如果我们已经在谈论forEach,请查看这个StackOverflow答案,我们就其一些缺点提供了一些有趣的见解。

streamMaxInteger() –使用Java 8流浏览列表:

public int streamMaxInteger() {Optional<Integer> max = integers.stream().reduce(Integer::max);return max.get();
}

优化基准

遵循本文的反馈意见,我们创建了基准的另一个版本。 与原始代码的所有差异都可以在此处查看 。 结果如下:

TL; DR:更改摘要

  1. 该列表不再易失。
  2. forMax2的新方法删除了字段访问。
  3. forEachLambda中的冗余帮助程序功能已修复。 现在,lambda也正在分配一个值。 可读性较差,但速度更快。
  4. 自动装箱消除了。 如果您在Eclipse中为项目打开自动装箱警告,则旧代码中有15条警告。
  5. 在reduce之前使用mapToInt修复流代码。

感谢Patrick Reinhart , Richard Warburton , Yan Bonnel , Sergey Kuksenko , Jeff Maxwell , Henrik Gustafsson以及所有在Twitter上发表评论的人!

基础

为了运行此基准测试,我们使用了Java Microbenchmarking Harness JMH。 如果您想了解更多有关如何在自己的项目中使用它的信息, 请查看这篇文章 ,我们将通过动手示例来了解它的一些主要功能。

基准配置包括JVM的2个分支,5个预热迭代和5个测量迭代。 这些测试是使用Java 8u66和JMH 1.11.2在c3.xlarge Amazon EC2实例(4个vCPU,7.5 Mem(GiB),2 x 40 GB SSD存储)上运行的。 完整的源代码可在GitHub上找到 ,您可以在此处查看原始结果输出。

话虽这么说,但有一点免责声明:基准往往非常危险,要正确地制定基准则非常困难。 尽管我们尝试以最准确的方式运行它,但始终建议您先花一点盐。

最后的想法

使用Java 8时,要做的第一件事是尝试使用lambda表达式和流。 但是要当心:感觉真的很好,很甜,所以您可能会上瘾! 我们已经看到,坚持使用迭代器和for-each循环的更传统的Java编程风格,明显优于Java 8提供的新实现。当然,情况并非总是如此,但是在这个非常常见的示例中,它表明可以大约差5倍。 如果它影响系统的核心部分或创建新的瓶颈,这会变得非常可怕。

翻译自: https://www.javacodegeeks.com/2015/11/benchmark-java-8-lambdas-streams-can-make-code-5-times-slower.html

基准测试:Java 8 Lambda和流如何使您的代码慢5倍相关推荐

  1. java lambda::_基准测试:Java 8 Lambda和流如何使您的代码慢5倍

    java lambda:: 与长期的实现相比,Java 8 lambda和流的性能如何? Lambda表达式和流在Java 8中受到了热烈的欢迎.这些是迄今为止很激动人心的功能,很长一段时间以来,它们 ...

  2. lambda 分类聚合_使用Java 8 Lambda,流和聚合

    lambda 分类聚合 总览 在本文中,我们将介绍使用Java 8 lambda,流和聚合来过滤和处理Collection中的对象. 这篇文章中的所有代码都可以在此处的 BitBucket中找到 . ...

  3. java生成pdf文件流_java 已经获取pdf代码,如何把他pdf文件保存到本机 要求用输出流做...

    展开全部 一.iText介绍 iText是着名的开放源码的站点sourceforge一个项目,是用于生成PDF文档的32313133353236313431303231363533e4b893e5b1 ...

  4. 10个Java 8 Lambda表达式经典示例

    Java 8 刚于几周前发布,日期是2014年3月18日,这次开创性的发布在Java社区引发了不少讨论,并让大家感到激动.特性之一便是随同发布的lambda表 达式,它将允许我们将行为传到函数里.在J ...

  5. Java 8 Lambda 表达式详解

    版权声明:本文由吴仙杰创作整理,转载请注明出处:https://segmentfault.com/a/1190000009186509 1. 引言 在 Java 8 以前,若我们想要把某些功能传递给某 ...

  6. java 怎么把list流化_Java 中的数据流和函数式编程

    原标题:Java 中的数据流和函数式编程 学习如何使用 Java 8 中的流 API 和函数式编程结构.-- Marty Kalin(作者) 当 Java SE 8(又名核心 Java 8)在 201 ...

  7. Java 8 Lambda表达式的函数式编程– Monads

    什么是monad ?: monad是一种设计模式概念,用于大多数功能编程语言(如Lisp)或现代世界的Clojure或Scala中. (实际上,我会从scala复制一些内容.)现在,为什么它在Java ...

  8. 深入浅出 Java 8 Lambda 表达式

    摘要:此篇文章主要介绍 Java8 Lambda 表达式产生的背景和用法,以及 Lambda 表达式与匿名类的不同等.本文系 OneAPM 工程师编译整理. Java 是一流的面向对象语言,除了部分简 ...

  9. Java 8 Lambda表达式10个示例【存】

    PS:不能完全参考文章的代码,请参考这个文件http://files.cnblogs.com/files/AIThink/Test01.zip 在Java 8之前,如果想将行为传入函数,仅有的选择就是 ...

最新文章

  1. 1.5 关于这门课-深度学习-Stanford吴恩达教授
  2. OSPF简单多区域及末梢区域配置
  3. cookie放在请求头_Web安全:你必须知道的“Cookie安全”
  4. 中国的这些民居都是你没见过的!
  5. TableStore发布多元索引功能,打造统一的在线数据平台
  6. python拟合曲线的方式,Python实现曲线拟合操作示例【基于numpy,scipy,matplotlib库】...
  7. 利用Attribute扩展MVC的Title和Sitemap
  8. 动物统计加强版 nyoj290
  9. Python遗传算法初学者教程
  10. 列车停站方案_基于节点分级的高速铁路列车停站方案设计策略
  11. PHP除数取余数,php相除取余数的实现方法
  12. 正则表达式高级学习技巧
  13. jQuery UI框架
  14. 深入学习VMware vSphere---基础知识
  15. java 读取excel数据
  16. excel文件被写保护怎么解除_excel表格受保护怎么解除保护
  17. C#控制利用模板文件通过BarTender控制斑马打印机打印
  18. Pygame 键盘输入
  19. html文件引入elementui该怎么做
  20. 高收益的次新股买卖技巧

热门文章

  1. Spring Boot定制启动图案
  2. 属于你们的“礼仪小课堂”
  3. layui如何实现添加数据时关闭页面层,并实时刷新表格数据?
  4. 《金色梦乡》金句摘抄(二)
  5. hibernate多对多、正向工程创建数据表——访问温馨提示
  6. 2020蓝桥杯省赛---java---A---2(既分数组)
  7. 利用树的先序和后序遍历打印os中的目录树
  8. Servlet请求和响应总结
  9. java项目:永和大王项目_Java项目:书评
  10. oracle 容器运行_Oracle应用容器云的自由