背景
Java 8引入了Lambda表达式,那么在Java 8中到底是如何实现Lambda表达式的呢? Lambda表达式经过编译之后,到底会生成什么东西呢?
在JAVA的世界中,万物皆对象,而对象模型是class(类),所以自然Lambda表达式最终也要通过类来表达。
实现
定义一个类实现Lambda表达式的接口, 并实现对应的方法,方法中完成具体的代码逻辑,在调用的地方,new出该类的对象并调用接口方法。(一般类,内部类,匿名内部类)
import java.util.function.Consumer;
public class Lambda1 {
public static void main(String[] args) {
Consumer c = s -> System.out.println(s);
c.accept("hello lambda");
}
}
对应生成类:
static class PrintExample implements Consumer {
@Override
public void accept(Object o) {
System.out.println(o);
}
}
public static void main(String[] args) {
new PrintExample().accept("hello lambda");
}
可以看到如上实现,最终效果是一致的。
JDK实现
那JDK的实现是如何的呢,为了探究Lambda表达式是如何实现的,就得需要研究Lambda表过式最终转化成的字节码文件
javap -p Lambda1. class
JDK生成的代码,多出一个私有静态方法private static void lambda$main$0
public class Lambda1 {
public Lambda1();
public static void main(java.lang.String[]);
private static void lambda$main$0(java.lang.Object);
}
这个私有的静态函数干的就是Lambda表达式里面的内容,那在Consumer的accept里是如何调到lambda$main$0呢?
通过断点,可以看到:

JDK 生成了一个另外一个类 Lambda1$Lambda$1,进入accept
此处生成的类名规则为:
类名格式如 <包名>.<类名>$Lambda$/.
number是由一个计数器生成counter.incrementAndGet()。
后缀/中的数字是一个hash值, 那就是类对象的hash值c.getClass().hashCode(),在Klass::external_name()中生成。

在accept里调用了上面生成的私有静态方法。
增加命令行,可以将中间生成的类Lambda1$Lambda$1输出
-Djdk.internal.lambda.dumpProxyClasses
生成的类反编译后如下
import java.lang.invoke.LambdaForm.Hidden;
import java.util.function.Consumer;
// $FF: synthetic class
final class Lambda1$Lambda$1 implements Consumer {
private Lambda1$Lambda$1() {
}
@Hidden
public void accept(Object var1) {
Lambda1.lambda$main$0(var1);
}
}
至此λ表达式的JDK实现原理,真想大白。
总结
JDK针对λ的实现,生成一个私有的静态方法(方法体里即具体执行逻辑)并生成的一个实现接口的类,并在回调里调用私有的静态方法。