java lamdba表达式效率_java8新特性Lambda表达式为什么运行效率低
Lambda表达式为什么运行效率低
准备
我为什么说Lambda表达式运行效率低。
先准备一个list:
先用Lambda表达式的方式来循环一下这个list:
运行时间大概为110ms
再用普通方式来循环一下这个list:
运行时间大概为0ms或1ms
你们没看错,运行时间差别就是这么大,不相信的话大家可以自己去试一下,并且这并不是只有在循环时使用Lambda表达式才会导致运行效率低,而是Lambda表达式在运行时就是会需要额外的时间,我们继续来分析。
分析
如果我们要研究Lambda表达式,最正确、最直接的方法就是查看它所对应的字节码指令。
使用以下命令查看class文件对应的字节码指令:
上述命令解析出来的指令非常多,我这里提取比较重要的部分来给大家分析:
使用Lambda表达式所对应的字节码指令如下:
不使用Lambda表达式所对应的字节码指令如下:
从上面两种方式所对应的字节码指令可以看出,两种方式的执行方式确实不太一样。
不使用Lambda表达式执行循环流程
字节码指令执行步骤:
82:invokestatic: 执行静态方法,java/lang/System.currentTimeMillis:();
85-92: 简单来说就是初始化数据,int i = 0;
93:invokeinterface:执行接口方法,接口为List,所以真正执行的是就是ArrayList.size方法;
98:if_icmpge: 比较,相当于执行i < list.size();
101:iinc: i++;
104:goto: 进行下一次循环;
107:invokestatic: 执行静态方法;
那么这个流程大家应该问题不大,是一个很正常的循环逻辑。
使用Lambda表达式执行循环流程
我们再来看一下对应的字节码指令:
字节码指令执行步骤:
34: invokestatic: 执行静态方法,java/lang/System.currentTimeMillis:();
37-38: 初始化数据
39: invokedynamic: 这是在干什么?
44: invokeinterface: 执行java/util/List.forEach()方法
49: invokestatic: 执行静态方法,java/lang/System.currentTimeMillis:();
和上面正常循环的方式的字节码指令不太一样,我们认真的看一下这个字节码指令,这个流程并不像是一个循环的流程,而是一个方法顺序执行的流程:
先初始化一些数据
执行invokedynamic指令(暂时这个指令是做什么的)
然后执行java/util/List.forEach()方法,所以真正的循环逻辑在这里
所以我们可以发现,使用Lambda表达式循环时,在循环前会做一些其他事情,所以导致执行时间要更长一点。
那么invokedynamic指令到底做了什么事情呢?
java/util/List.forEach方法接收一个参数Consumer super T> action,Consumer是一个接口,所以如果要调用这个方法,就要传递该接口类型的对象。
而我们在代码里实际上是传递的一个Lambda表达式,那么我们这里可以假设:需要将Lambda表达式转换成对象,且该对象的类型需要根据该Lambda表达式所使用的地方在编译时期进行反推。
这里在解释一下反推:一个Lambda表达式是可以被多个方法使用的,而且这个方法所接收的参数类型,也就是函数式接口,是可以不一样的,只要函数式接口符合该Lambda表达式的定义即可。
本例中,编译器在编译时可以反推出,Lambda表达式对应一个Cosumer接口类型的对象。
那么如果要将Lambda表达式转换成一个对象,就需要有一个类实现Consumer接口。
所以,现在的问题就是这个类是什么时候生成的,并且生成在哪里了?
所以,我们慢慢的应该能够想到,invokedynamic指令,它是不是就是先将Lambda表达式转换成某个类,然后生成一个实例以便提供给forEach方法调用呢?
我们回头再看一下invokedynamic指令:
Java中调用函数有四大指令:invokevirtual、invokespecial、invokestatic、invokeinterface,在JSR 292 添加了一个新的指令invokedynamic,这个指令表示执行动态语言,也就是Lambda表达式。
该指令注释中的#0表示的是BootstrapMethods中的第0个方法:
所以invokedynamic执行时,实际上就是执行BootstrapMethods中的方法,比如本例中的:java/lang/invoke/LambdaMetafactory.metafactory。
代码如下:
这个方法中用到了一个特别明显且易懂的类:InnerClassLambdaMetafactory。
这个类是一个针对Lambda表达式生成内部类的工厂类。当调用buildCallSite方法是会生成一个内部类并且生成该类的一个实例。
那么现在要生成一个内部类,需要一些什么条件呢:
类名:可按一些规则生成
类需要实现的接口:编译时就已知了,本例中就是Consumer接口
实现接口里面的方法:本例中就是Consumer接口的void accept(T t)方法。
那么内部类该怎么实现void accept(T t)方法呢?
我们再来看一下javap -v -p Test.class的结果中除开我们自己实现的方法外还多了一个方法:
很明显,这个静态的lambda$main$0方法代表的就是我们写的Lambda表达式,只是因为我们例子中Lambda表达式没写什么逻辑,所以这段字节码指令Code部分也没有什么内容。
那么,我们现在在实现内部类中的void accept(T t)方法时,只要调用一个这个lambda$main$0静态方法即可。
所以到此,一个内部类就可以被正常的实现出来了,内部类有了之后,Lambda表达式就是可以被转换成这个内部类的对象,就可以进行循环了。
java lamdba表达式效率_java8新特性Lambda表达式为什么运行效率低相关推荐
- java lambda表达式详解_Java8新特性Lambda表达式详解
课程目标: 通过本课程的学习,详细掌握Java8新特性之Lambda表达式: 适用人群:有Java基础的开发人员: 课程概述:从Java 8出现以来lambda是最重要的特性之一,它可以让我们用简洁流 ...
- java三目表达式_Java8新特性Lambda表达式
1 Lambda表达式 对于很多计算机语言来说,Lambda表达式并不是陌生的语法格式,而对于Java而言,它的到来比较晚,直到Java8更新之后,Lambda表达式才正式出现在Java语法中.所以如 ...
- java lambda表达式详解_java8新特性-Lambda表达式的详解(从0开始)
这几天复习了java8的一些新特性,作为一个从java5以来最具革命性的版本,一直没有来得及总结.本系列文章主要是从<java8实战>总结的.这是第一篇文章主要介绍java8的lambda ...
- 【Java】jdk 1.8 新特性——Lambda表达式
Lambda表达式 jdk 1.8 新加入的特性,简化了简单接口的实现 函数式接口 函数式中只有一个待实现的方法,可以使用@FunctionalInterface注解标注函数式接口.这个接口中只能有一 ...
- java8 lambda判断_Java8新特性-Lambda表达式
Predicate接口使用 请在测试类main方法中完成以下需求 已知有Integer[] arr = {-12345, 9999, 520, 0,-38,-7758520,941213} a) 使用 ...
- Java 8 新特性 lambda表达式
/ Created by Manager on 2021/4/1. Java 8 新特性 lambda表达式 StreamAPI 新日期 新注解 */ 视频连接 1https://www.bilibi ...
- Java 8 新特性Lambda 表达式
Java 8 新特性Lambda 表达式 一.常用循环 二.匿名内部类 三.排序集合 四.循环打印对象 五.根据条件修改 六.排序 七.求和 八.统计方法 九.材料 一.常用循环 public cla ...
- java新特性lambda表达式快速入门
文章目录 序 常规写法 写法一:新建类并实现该接口 写法二:使用匿名函数 lambda写法 写法一:lambda常规写法 写法二:lambda简写 中场疑问 lambda的方法引用 写法一 写法二 练 ...
- Java8新特性----Lambda表达式详细探讨
Java8新特性 Lambda表达式 入门演示 案例1 如何解决 cannot be cast to java.lang.Comparable问题? 案例2 优化方式一 : 策略设计模式 优化方式二: ...
最新文章
- SQL语言 之 数据查询
- 百度api:根据经纬度获取地理位置信息
- 如何实际使用强类型Dataset(键盘再也不需要敲入表名和字段名了)
- bootstrap-multiselect样式修改
- 初始化 数组 java_如何用Java初始化数组
- BZOJ 3831 POI2014 Litter Bird
- python折线图实线虚线_python – matplotlib中的虚线而不是缺失值
- 四大银行(工建农中)大数据进展如何?
- 数据统计学习的5个基本流程
- FPGA实现SPI 协议
- NSIS 注册DLL OCX
- 最全面测试计划书模板
- TimeZone.getTimeZone 时区参数说明
- 利用OpenCV实现一个简单的实时人脸检测项目并显示FPS
- CCITT对媒体的分类
- SAP中的电子数据交换EDI
- 瓦伦达心态——再谈工作中的专注和心态
- 大数据架构选型与设计
- 鸿蒙实力等级划分,从综漫开始的万界之旅
- 招聘 iOS 全栈工程师 欢迎加入 ArcBlock 中国研发中心
热门文章
- “智慧血联网平台”亮相军民融合技术装备博览会
- 【转载】有软件开发,就要有软件测试!
- node.js学习笔记之promise
- 电脑中所有exe文件无法运行解决方案
- Cisco *** 完全配置指南-连载-PIX和ASA连接的故障诊断与排除
- 点点看 只有想不到没有看不到
- Python基础14-迭代器与生成器
- 关系数据库非关系数据库_如何与关系数据库最佳配合
- 10、同步机制遵循的原则_我要遵循的10条原则
- vs2017 open从v_宣布#Open2017,这是面向开发人员的除夕直播流