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表達式首次調用的時候,進行轉換和鏈接;之后的調用都會跳過這一步驟