• 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表达式首次调用的时候,进行转换和链接;之后的调用都会跳过这一步骤

  • 相关阅读:
    BZOJ 2326 数学作业
    BZOJ 4448 情报传递
    BZOJ 4443 小凸玩矩阵
    BZOJ 1852 最长不下降序列
    BZOJ 4373 算术天才⑨与等差数列
    68285
    65656556
    D. Points in rectangle
    恐怖的怪物
    再战斐波那契
  • 原文地址:https://www.cnblogs.com/linlf03/p/12659600.html
Copyright © 2020-2023  润新知