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

随着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
例子1
这时候我们编译后,可以看到两个class文件
这里写图片描述

我们再看看lambda表达式的例子lambda表达式 LambdaTest
这里写图片描述
然而class文件只有一个:LambdaTest.class
所以,真像永远只有一个:很显然lambda和匿名内部类不是同一个东西

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

具体的,以后有时间会专门写博文分享,但是lambda的大致思路如下:
1. lamdba表达式被编译生成当前类的一个私有静态方法
2. 在原调用Lamdba方法的地方编译成了一个invokedynamic指令调用,同时呢也生成了一个对应的BootstrapMethod
3. 当lamdba表达式被JVM执行,也就是碰到2中说到的invokedynamic指令,该指令引导调用LambdaMetafactory.metafactory方法,该方法返回一个CallSite实例
4. 而这个CallSite实例中的target对象,也就是直接引用到一个MethodHandle实例,而这个MethodHandle实例会调用到1中生成的静态方法,在上面的例子就是lambda$main$0这个方法,完成整个lamdba表达式的使用

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

猜你喜欢

转载自blog.csdn.net/f641385712/article/details/81238465