Java8(4)Lambda表达式的真实面目

前面三篇讲了lambda表达式的一些基本概念和核心类Stream的基本操作,那么lambda表达式的实现原理到底是怎么样的呢?

我们以前创建Runnable的时候是用匿名内部类的方式实现,而有lambda表达式之后,代码变得很简洁,很方便。代码如下:

Runnable r = new Runnable() {
    @Override
    public void run() {
        System.out.println();
    }
};
Runnable r = () -> System.out.println();

所以对于lambda表达式实现原理的直接想法就是通过创建匿名内部类实现的。事实到底如何呢?我们可以通过反编译的方式进行验证。

public class LambdaTest {

    public static void output(String s, Function<String> fun) {
        fun.out(s);
    }

    public static void main(String[] args) {
        String str = "hello ";
        output("world", x -> System.out.println(str + x));
    }

}

@FunctionalInterface
interface Function<T> {
    void out(T x);
}

通过cmd输入javap -p LambdaTest,可以得到下面的信息:

Compiled from "LambdaTest.java"
public class cn.tl.test.LambdaTest {
    public cn.tl.test.LambdaTest();
    public static void output(java.lang.String, cn.tl.test.Function<java.lang.String>);
    public static void main(java.lang.String[]);
    private static void lambda$main$0(java.lang.String, java.lang.String);
}

跟原代码相比,多了一个私有静态方法lambda$main$0

执行代码的时候,我们还可以通过在IDEA上的VM options栏加上-Djdk.internal.lambda.dumpProxyClasses,可以看到生成了一个类LambdaTest$$Lambda$1。它是通过LambdaMetafactorymetafactory方法动态生成的。反编译代码如下:

final class LambdaTest$$Lambda$1 implements Function {
    private final String arg$1;

    private LambdaTest$$Lambda$1(String var1) {
        this.arg$1 = var1;
    }

    private static Function get$Lambda(String var0) {
        return new LambdaTest$$Lambda$1(var0);
    }

    @Hidden
    public void out(Object var1) {
        LambdaTest.lambda$main$0(this.arg$1, (String)var1);
    }
}

通过以上的代码,也就可以看出不是通过匿名内部类实现的,而是通过内部类+私有静态方法实现的。(为什么是内部类?因为调用了LambdaTest类的私有静态方法lambda$main$0。)

还有为什么lambda表达式引用的局部变量不能改变的原因也显而易见,因为局部变量是final类型的,只不过声明的时候不用写final关键字,而JDK8之前匿名内部类强制写final关键字。因此最终的Lambda表达式大概等价于以下形式:

public class LambdaTest {

    public static void output(String s, Function<String> fun) {
        fun.out(s);
    }

    public static void main(String[] args) {
        String str = "hello ";

        output("world", x -> System.out.println(str + x));

        output("world", new LambdaTest().new LambdaTest$$Lambda$1(str));
    }

    //lambda表达式生成一个私有静态方法,表达式右边为方法体,涉及到的变量全部作为方法参数
    private static void lambda$main$0(String arg0, String x) {
        System.out.println(arg0 + x);
    }

    //函数式接口实现类,复写方法调用私有静态方法
    final class LambdaTest$$Lambda$1 implements Function {
        private final String arg$1;

        private LambdaTest$$Lambda$1(String var1) {
            this.arg$1 = var1;
        }
        //该方法报错不应该是static,功能暂时不明。
        private static Function get$Lambda(String var0) {
            return new LambdaTest$$Lambda$1(var0);
        }

        public void out(Object var1) {
            LambdaTest.lambda$main$0(this.arg$1, (String) var1);
        }
    }
}


@FunctionalInterface
interface Function<T> {
    void out(T x);
}
    原文作者:Namikun
    原文地址: https://www.jianshu.com/p/50cc329ad169
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞