Java 8 Lambda表達式實現原理解析


Lambda原理

在Java8中每一個表達式必須有一個函數式接口與之對應。

 

什么函數式接口?

簡單的說就是只包含一個抽象方法的普通接口

 

Lambda表達式的使用

我們定義了一個IMath接口,加上@FunctionalInterface注解

public class LambdaTest {

    @FunctionalInterface
    interface IMath{
        int operation(int a, int b);
    }
    

    int testLambda(IMath lambdaTest, int a , int b) {
      return lambdaTest.operation(a,b);
    }

    public static void main(String[] args) {
        LambdaTest lambdaTest = new LambdaTest();

        int result = lambdaTest.testLambda(
                (a,b) -> a + b
                , 1, 2);
        System.out.println(result);
    }
}

  然后定義一個testLambda方法,最終在main方法中使用lambda表達式。

 

1、使用字節碼查看工具 javap -p LambdaTest.class

-p表示輸出所有的類及成員

Compiled from "LambdaTest.java"
public class java8.LambdaTest {
  public java8.LambdaTest();
  int testLambda(java8.LambdaTest$IMath, int, int);
  public static void main(java.lang.String[]);
  private static int lambda$main$0(int, int);
}

  可以看到生成了一個源碼沒有的私有的靜態函數private static int lambda$main$0(int, int);

如何實現這個私有靜態方法呢?我們在LambdaMetafactory類中的metafactory方法上打上斷點

 

 最終進入metafactory這個方法

    public static CallSite metafactory(MethodHandles.Lookup caller,
                                       String invokedName,
                                       MethodType invokedType,
                                       MethodType samMethodType,
                                       MethodHandle implMethod,
                                       MethodType instantiatedMethodType)
            throws LambdaConversionException {
        AbstractValidatingLambdaMetafactory mf;
        mf = new InnerClassLambdaMetafactory(caller, invokedType,
                                             invokedName, samMethodType,
                                             implMethod, instantiatedMethodType,
                                             false, EMPTY_CLASS_ARRAY, EMPTY_MT_ARRAY);
        mf.validateMetafactoryArgs();
        return mf.buildCallSite();
    }

  這個函數的作用: 為Lambda表達式生成一個內部類。這個類是怎么樣的?

 

2、查看metafactory函數生成的內部類

在Idea 的VM options配置-Djdk.internal.lambda.dumpProxyClasses

 

 運行后,會將生成的內部類class輸出到一個文件中

package java8;

import java.lang.invoke.LambdaForm.Hidden;
import java8.LambdaTest.IMath;

// $FF: synthetic class
final class LambdaTest$$Lambda$1 implements IMath {
    private LambdaTest$$Lambda$1() {
    }

    @Hidden
    public int operation(int var1, int var2) {
        return LambdaTest.lambda$main$0(var1, var2);
    }
}

  最終調用的是LambdaTest的內部私有靜態方法 lambda$main$0(var1, var2);

 總結:Lambda並不是采用內部類的實現方式實現的。如果Lambda表達式使用內部類的方式,將是極為不利的。類加載需要有加載、驗證、准備、解析、初始化等過程,大量的內部類將會影響應用執行的性能,並消耗Metaspace。 Lambda表達式首次調用的時候,進行轉換和鏈接;之后的調用都會跳過這一步驟


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM