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

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

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

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

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

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

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

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

**记录的最大错误是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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/355697.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ssm框架逻辑删除mysql_MybatisPlus--CRUD接口及主键增长策略、自动填充、乐观锁更新数据...

目录一、insert1、插入操作2、主键策略二、update1、根据Id更新操作2、自动填充3、乐观锁三、select1、根据id查询记录2、通过多个id批量查询3、简单的条件查询4、分页四、delete1、根据id删除记录2、批量删除3、简单的条件查询删除4、逻辑删除一、insert1、插入操作RunWith(Sp…

python对英语的要求_学python需要英语基础吗

在很多人的眼里&#xff0c;学习编程需要英语基础&#xff0c;因为程序代码全是英文字母&#xff0c;如果没有英语基础可能很难学懂编程。程序代码是英文确实没有错&#xff0c;但是也不是必须得懂英语&#xff0c;因为计算机程序有自己语言&#xff0c;并不是我们生活中的英语…

python找不到csv文件_Python如何读取csv文件

逗号分隔值&#xff08;Comma-Separated Values&#xff0c;CSV&#xff0c;有时也称为字符分隔值&#xff0c;因为分隔字符也可以不是逗号&#xff09;&#xff0c;其文件以纯文本形式存储表格数据&#xff08;数字和文本&#xff09;。纯文本意味着该文件是一个字符序列&…

python cv2模块imshow_Python-OpenCV:cv2.imread(),cv2.imshow(),cv2.imwrite()

一、需要工具本机使用python 2.7.10下调试代码均通过&#xff0c;一下学习需要有一定的代码阅读能力&#xff0c;一下学习只介绍函数方法&#xff1a;Python 作为一种高效简洁的直译式语言非常适合我们用来解决日常工作的问题。而且它简单易学&#xff0c;初学者几个小时就可以…

2016年将是Java终于拥有窗口函数的那一年!

你没听错。 到目前为止&#xff0c;出色的窗口功能是SQL独有的功能。 即使是复杂的函数式编程语言似乎也缺少这种漂亮的功能&#xff08;如果我记错了&#xff0c;请纠正我&#xff0c;Haskell伙计们&#xff09;。 我们撰写了许多有关窗口函数的博客文章&#xff0c;并在诸如…

android 仿京东地址选择_Android 开发:仿美团地址选择

最近做了这个功能&#xff0c;分享一下&#xff0c;用的是百度地图api&#xff0c;和美团外卖的地址选择界面差不多&#xff0c;也就是可以搜索或者滑动地图展示地址列表给用户选择&#xff0c;看下效果图先。文章重点展示地图并定位到“我”的位置 滑动地图获取周边poi(逆地理…

ps还原上一步快捷键_ps还原上一步快捷键_photoshop恢复上一步操作的快捷键是什么...

满意答案simonsinxer推荐于 2017.09.01采纳率&#xff1a;53% 等级&#xff1a;11已帮助&#xff1a;63469人还原/重做前一步操作 【Ctrl】【Z】其他一些快捷键&#xff1a;还原两步以上操作 【Ctrl】【Alt】【Z】重做两步以上操作 【Ctrl】【Shift】【Z】剪切选取的图像或路…

python中排序从小到大_从Python看排序:冒泡排序

冒泡排序在排序算法中是最简单的一种&#xff0c;它通过多次遍历列表&#xff0c;将最大的元素冒泡到列表的头部或尾部。我们通过对四张扑克牌&#xff08;花色相同&#xff09;以从小到大的方式进行排序来演示该算法的工作原理。首先将扑克牌面朝上放在桌上&#xff0c;如下图…

c语言三个数从小到大排序/输出_我的c语言笔记(三)

int表达式这个表达式存在的目的在于将表达式转为整数。比如&#xff1a;float a9999.9999&#xff1b;int b;b(int)(a/1000);就可以得到9啦&#xff0c;别忘了套上固定格式哦&#xff5e;然后我们接下来一起来做一道很重要的题哦&#xff0c;反复练习&#xff0c;可以顺利拿下同…

java虚拟_Java虚拟机(JVM)工作原理

虽然本教程的内容为 x86 处理器的原生汇编语言&#xff0c;但是了解其他机器架构如何工作也是有益的。JVM 是基于堆栈机器的首选示例。JVM 用堆栈实现数据传送、算术运算、比较和分支操作&#xff0c;而不是用寄存器来保存操作数(如同 x86 一样)。数据结构&#xff0c;让它们协…

java string blob_java String类型转换为Blob类型

展开全部这个是mysql下存取blob字段的一个很简单的类&#xff0c;跟据自己的需要32313133353236313431303231363533e4b893e5b19e31333332623936改改就行了/*** Title: BlobPros.java* Project: test* Description: 把图片存入mysql中的blob字段&#xff0c;并取出* Call Module…

Neo4j:特定关系与一般关系+属性

为了在Neo4j查询中获得最佳的遍历速度&#xff0c;我们应该使关系类型尽可能具体 。 让我们看一下几周前我在Skillsmatter上发表的“ 建模建议引擎建模 ”演讲中的一个例子。 我需要决定如何为成员和事件之间的“ RSVP”关系建模。 一个人可以对事件表示“是”或“否”&#…

java 按位置格式化字符串_Java字符串格式化,{}占位符根据名字替换实例

我就废话不多说了&#xff0c;大家还是直接看代码吧~import java.beans.PropertyDescriptor;import java.lang.reflect.Method;import java.util.HashMap;import java.util.Map;import java.util.regex.Matcher;import java.util.regex.Pattern;public class StringFormatUtil …

Apache Drill 1.4性能增强的简要概述

今天&#xff0c;我们很高兴宣布Apache Drill 1.4现已在MapR发行版中可用。 钻1.4是MAPR生产就绪和支持的版本&#xff0c;可以从下载这里 &#xff0c;找到1.4版本说明这里 。 Drill 1.4以其高度灵活和可扩展的体系结构为基础&#xff0c;带来了多种新功能以及对查询性能的增…

【01背包】洛谷P1282多米诺骨牌

题目描述 多米诺骨牌有上下2个方块组成&#xff0c;每个方块中有1~6个点。现有排成行的 上方块中点数之和记为S1&#xff0c;下方块中点数之和记为S2&#xff0c;它们的差为|S1-S2|。例如在图8-1中&#xff0c;S161119&#xff0c;S2153211&#xff0c;|S1-S2|2。每个多米诺骨牌…

java geolitecity_GeoLite2 Java根据IP获得城市、经纬度

之前我们介绍过通过 qqwry.dat 根据IP获得所属城市和运营商信息。但是这个 qqwry.dat 已经太久没更新了&#xff0c;数据有些不准确&#xff0c;而且现在我们有个需求就是想获取某个IP所在的经纬度。这里我们可以使用 GeoLite2&#xff0c;这个是国外开源的一个库&#xff0c;需…

计算机专业英语第二版张强华翻译_计算机语言发展的三个阶段,机器语言、汇编语言与高级语言...

在如今信息发达的时代&#xff0c;科技日新月异&#xff0c;计算机和Internet网络的发展也成为人们日常生活的重要部分。学习一两门计算机编程语言也如当初学习英文一样的火热&#xff0c;随着人工智能AI和云计算的不断发展&#xff0c;Python语言和Scala语言已经成为这两个领域…

使用Apache Drill REST API通过Node构建ASCII仪表板

Apache Drill有一个隐藏的瑰宝&#xff1a;易于使用的REST接口。 该API可用于查询&#xff0c;分析和配置Drill引擎。 在此博客文章中&#xff0c;我将说明如何使用Brilled Contrib使用Drill REST API创建ascii仪表板。 ASCII仪表盘如下所示&#xff1a; 先决条件 Node.js …

影子场vs.属性访问器接口第2轮

如果你们还没有注意到Dirk Lemmerman和我之间的&#xff08;轻松&#xff09; 对决 &#xff0c;那么让我快速提及一下我们是如何做到这一点的。 首先&#xff0c;Dirk创建了JavaFX技巧23&#xff1a;“ 为属性保存内存阴影字段 ”&#xff0c;以帮助应用程序开发人员在使用Jav…

Lowest Common Ancestor of a Binary Search Tree a Binary Tree

235. Lowest Common Ancestor of a Binary Search Tree 题目链接&#xff1a;https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-search-tree/#/description 题目大意&#xff1a;给定一棵二叉查找树和两个节点p和q&#xff0c;要求返回这两个节点的第一个公共…