【小家java】使用lambda表达式传参是否有性能问题?

简介: 【小家java】使用lambda表达式传参是否有性能问题?

相关阅读


【小家java】java5新特性(简述十大新特性) 重要一跃

【小家java】java6新特性(简述十大新特性) 鸡肋升级

【小家java】java7新特性(简述八大新特性) 不温不火

【小家java】java8新特性(简述十大新特性) 饱受赞誉

【小家java】java9新特性(简述十大新特性) 褒贬不一

【小家java】java10新特性(简述十大新特性) 小步迭代

【小家java】java11新特性(简述八大新特性) 首个重磅LTS版本


每篇一句

永远要活给自己看,不要在乎别人的指指点点。只要做好你自己,让看不起的人高攀不起,让看不起你的人更喜欢你


随着java8的普及,lambda表达式的书写日益增多。咱们看下面一个例子:

编程有一条原则如下:


避免创建不必要的对象:最好能重用对象,而不要在每次需要的时候就创建一个相同功能的新对象。

List<String> names = Arrays.asList("peter", "anna", "mike", "xenia");
 // 1、匿名内部类
Collections.sort(names, new Comparator<String>() {
    @Override
    public int compare(String a, String b) {
        return b.compareTo(a);
    }
});
//2、lambda表达式
Collections.sort(names, (a, b) -> b.compareTo(a));


如果比较器,如果我们需要使用多次,其实可以在外面定义一个比较器对象,然后直接使用就成,不用每次都new一个内部类吧?


那么问题来了:是不是每次排序都创建了一个新的Comparator对象,导致性能降低?那么还主张使用Lambda表达式吗?


回答一:


1.可以静态声明一个Lambda表达式内部匿名类对象;

2.朝生夕灭的小对象对JVM来说不是大问题;


回答二:


1.每次排序并不会创建一个新的 Comparator 对象,一般情况下 Lambda 表达式对应的实例(instance)一旦在内存中产生,那么 JVM 在当前环境下会重复使用这个实例。

2.在可以提升程序可读性和开发效率的前提下,主张使用 Lambda 表达式(这是它最现实的意义所在)

分析:lambda表达式原理

根本原因:

Lamdba表示根本就不是匿名内部类的语法糖,也就是说Lambda表达式底层实现不是匿名内部类的实现方式,他们其实两个东西。

证明如下:

匿名内部类其实在编译的时候会生成一个类文件,命名以ClassName$数字的方式,所以要是Lamdba表达式底层也是由匿名内部类的方式实现的话,那肯定也会生成一个同样类似的内文件

所以我们简单把你的例子分别写在不同包下面的类,再在来检查编译后的效果

匿名内部类实现 InnerTest


image.png


这时候我们编译后,可以看到两个class文件


image.png


我们再看看lambda表达式的例子lambda表达式 LambdaTest


image.png


然而class文件只有一个:LambdaTest.class

所以,真像永远只有一个:很显然lambda和匿名内部类不是同一个东西


那Lamdba表达式是怎么实现的?


具体的,以后有时间会专门写博文分享,但是lambda的大致思路如下:


    1.lamdba表达式被编译生成当前类的一个私有静态方法

    2.在原调用Lamdba方法的地方编译成了一个invokedynamic指令(java7 JVM中增加了一个新的指令)调用,同时呢也生成了一个对应的BootstrapMethod

    3.当lamdba表达式被JVM执行,也就是碰到2中说到的invokedynamic指令,该指令引导调用LambdaMetafactory.metafactory方法,该方法返回一个CallSite实例


   4.而这个CallSite实例中的target对象,也就是直接引用到一个MethodHandle实例,而这个MethodHandle实例会调用到1中生成的静态方法,在上面的例子就是lambda$main$0这个方法,完成整个lamdba表达式的使用


其实可以看到lamdba表达式在某种意义上的确比匿名内部类好很多,可读性还是大优势~哈哈,我要说大势,是因为lamdba表达式后续可以优化的空间更广,反正我是在java中用惯了,相当喜欢

关于lambda的性能问题(测试)


有许许多多关于 Java 8 中流效率的讨论,其中最著名要属这篇译文了:Java8 Lambda表达式和流操作如何让你的代码变慢5倍

看标题是不是感觉有点不敢用lambda了呢?我觉得还是不能人云亦云,还是自己测试一把吧~~~~


下面Demo用稍微真是一点的场景测试,而不是单纯的数字计算,这样应该更具有说服力些~


public class Person {
    public String name;
    public Integer age;
    // 省略get set方法
}
// Main方法测试
    public static void main(String[] args) {
        int count = 10000;
        List<Person> personList = new ArrayList<>();
        for (int i = 0; i < count; i++) {
            personList.add(new Person("fsx", 18 + i));
        }
        Instant start = Instant.now();
        //getAgesWithLambda(personList);
        getAges(personList);
        System.out.println("耗时:" + Duration.between(start, Instant.now()).toMillis() + "ms");
    }
  // 使用lambda表达式方式~
    private static List<Integer> getAgesWithLambda(List<Person> personList) {
        return personList.stream().map(Person::getAge).collect(Collectors.toList());
    }
  // 使用普通方式~
    private static List<Integer> getAges(List<Person> personList) {
        List<Integer> ages = new ArrayList<>();
        for (Person person : personList) {
            ages.add(person.getAge());
        }
        return ages;
    }

当count=1000时:getAges(1ms) getAgesWithLambda(70ms)

当count=10000时:getAges(2ms) getAgesWithLambda(71ms)

当count=100000时:getAges(10ms) getAgesWithLambda(76ms)

当count=1000000时:getAges(21ms) getAgesWithLambda(101ms)

当count=10000000时:getAges(619ms) getAgesWithLambda(738ms)


从上面测试,我得出如下两个结论,不知道小伙伴同意不?


1.从人的角度,代码可读性方面lambda表达式更佳,并且可维护性更好


2.性能上当量非常大时,lambda的表现并不比普通方式差


所以我坚持:lambda表达式,非常推荐使用。毕竟我认为代码永远是人看得懂看得舒服才是第一位,其次才是机器~

(虽然量不大的时候lambda比普通方式差,但是既然量都不大怎么可能会有性能问题呢?完全可以忽略嘛~)


说明:测试机器为I5普通pc笔记本,各位不同机器上测试效果(耗时)上可能会有出入~


相关文章
|
27天前
|
机器学习/深度学习 Java 编译器
解锁硬件潜能:Java向量化计算,性能飙升W倍!
编译优化中的机器相关优化主要包括指令选择、寄存器分配、窥孔优化等,发生在编译后端,需考虑目标平台的指令集、寄存器、SIMD支持等硬件特性。向量化计算利用SIMD技术,实现数据级并行,大幅提升性能,尤其适用于图像处理、机器学习等领域。Java通过自动向量化和显式向量API(JDK 22标准)支持该技术。
64 4
|
25天前
|
安全 Java API
Java中的Lambda表达式:简洁与功能的结合
Java中的Lambda表达式:简洁与功能的结合
183 91
|
25天前
|
安全 Java
Java中的Switch表达式:更简洁的多路分支
Java中的Switch表达式:更简洁的多路分支
197 91
|
1月前
|
Cloud Native 前端开发 Java
WebAssembly 与 Java 结合的跨语言协作方案及性能提升策略研究
本文深入探讨了WebAssembly与Java的结合方式,介绍了编译Java为Wasm模块、在Java中运行Wasm、云原生集成等技术方案,并通过金融分析系统的应用实例展示了其高性能、低延迟、跨平台等优势。结合TeaVM、JWebAssembly、GraalVM、Wasmer Java等工具,帮助开发者提升应用性能与开发效率,适用于Web前端、服务器端及边缘计算等场景。
71 0
|
2月前
|
自然语言处理 Java Apache
在Java中将String字符串转换为算术表达式并计算
具体的实现逻辑需要填写在 `Tokenizer`和 `ExpressionParser`类中,这里只提供了大概的框架。在实际实现时 `Tokenizer`应该提供分词逻辑,把输入的字符串转换成Token序列。而 `ExpressionParser`应当通过递归下降的方式依次解析
193 14
|
1月前
|
Java 编译器
Java 17 Switch表达式:更简洁、更强大的流程控制
Java 17 Switch表达式:更简洁、更强大的流程控制
|
2月前
|
设计模式 数据采集 Java
Java正则表达式的基础知识,进阶至熟练掌握。
通过大量的练习来熟悉它们的识别模式、如何设计模式来解决实际问题,才能够逐步达到熟练掌握。更多的是通过实践、编写代码和解决真实问题来完善技能。在这方面,没有快速的捷径,唯有刻意练习和长时间的代码实践。
63 0
|
3月前
|
SQL JSON 安全
Java 8 + 中 Lambda 表达式与 Stream API 的应用解析
摘要:本文介绍了Java 8+核心新特性,包括Lambda表达式与Stream API的集合操作(如过滤统计)、函数式接口的自定义实现、Optional类的空值安全处理、接口默认方法与静态方法的扩展能力,以及Java 9模块化系统的组件管理。每个特性均配有典型应用场景和代码示例,如使用Stream统计字符串长度、Optional处理Map取值、模块化项目的依赖声明等,帮助开发者掌握现代Java的高效编程范式。(150字)
66 1
|
9月前
|
Java API 开发者
Java中的Lambda表达式与Stream API的协同作用
在本文中,我们将探讨Java 8引入的Lambda表达式和Stream API如何改变我们处理集合和数组的方式。Lambda表达式提供了一种简洁的方法来表达代码块,而Stream API则允许我们对数据流进行高级操作,如过滤、映射和归约。通过结合使用这两种技术,我们可以以声明式的方式编写更简洁、更易于理解和维护的代码。本文将介绍Lambda表达式和Stream API的基本概念,并通过示例展示它们在实际项目中的应用。