首頁  >  問答  >  主體

java - 使用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));

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

阿神阿神2713 天前1107

全部回覆(3)我來回復

  • 天蓬老师

    天蓬老师2017-04-18 10:55:20

    先回答你的問題:
    是不是每次排序都創建了一個新的Comparator對象,導致效能降低?那麼還主張使用Lambda表達式嗎?
    不是,主張

    1. 根本原因
      Lamdba表示根本就不是匿名內部類別的語法糖,也就是說Lambda表達式底層實作不是匿名內部類別的實作方式,他們其實兩個東西

    2. 怎麼證明呢?
      匿名內部類別其實在編譯的時候會產生一個類別文件,命名以ClassName$數字的方式,所以要是Lamdba表達式底層也是由匿名內部類別的方式實現的話,那肯定也會產生一個同樣類似的內文件
      所以我們簡單把你的例子分別寫在不同包下面的類,再在來檢查編譯後的效果
      匿名內部類實現InnerTest


      這是class文件,可以看到有兩個

      lambda表達式 LamdbaTest

      然而class檔案只有一個


      所以真相只有一個,哈哈,很顯然,這根本就不是一個東西嘛

    3. 那Lamdba表達式是怎麼達成的?
      我們可以來看看他們的字節碼,這樣骨子裡的不一樣就完全展示出來了
      InnerTest

      LamdbaTest

      可以看到兩者使用的指令都是不一樣的,Lamdba表達式在解析時,使用的是Java7新增的invokedynamic指令,如果你熟悉你這個指令的話,那就可能瞬間明白了,不熟悉的話,你可以問問度娘
      不過你可以直接從這個指令名字體會出:動態調用
      因此,其實不同於匿名內部類別被編譯成一個類別文件,Lamdba表達式是被編譯成了一個靜態方法,我們-p可以再看一次就知道了,生成的方法名叫lambda$main

      🎜
    所以结合之前两个反编译的结果可以看到,lamdba表达式运行整体思路大致如下  
        1. lamdba表达式被编译生成当前类的一个私有静态方法  
        2. 在原调用Lamdba方法的地方编译成了一个invokedynamic指令调用,同时呢也生成了一个对应的BootstrapMethod  
        3. 当lamdba表达式被JVM执行,也就是碰到2中说到的invokedynamic指令,该指令引导调用LambdaMetafactory.metafactory方法,该方法返回一个CallSite实例
        4. 而这个CallSite实例中的target对象,也就是直接引用到一个MethodHandle实例,而这个MethodHandle实例会调用到1中生成的静态方法,在上面的例子就是`lambda$mainrrreee`这个方法,完成整个lamdba表达式的使用  
    1. 再說一句
      其實可以看到lamdba表達式在某種意義上的確比匿名內部類好很多,無論是性能,可讀性還是大勢~哈哈,我要說大勢,是因為lamdba表達式後續可以優化的空間更廣,反正我是在java中用慣了,相當喜歡

    回覆
    0
  • 阿神

    阿神2017-04-18 10:55:20

    1. 每次排序並不會創建一個新的 Comparator 對象,一般情況下 Lambda 表達式對應的實例(instance)一旦在內存中產生,那麼 JVM 在當前環境下會重複使用這個實例。具體的說明,可以參考這個連結:Run-Time Evaluation of Lambda Expressions

    2. 在可以提升程式可讀性和開發效率的前提下,主張使用 Lambda 表達式

    回覆
    0
  • 怪我咯

    怪我咯2017-04-18 10:55:20

    1. 可以靜態宣告一個Lambda表達式內部匿名類別物件;

    2. 朝生夕滅的小對象對JVM來說不是大問題;

    回覆
    0
  • 取消回覆