当我刚刚开始学习Java的Lambda的时候,我曾经完全误解了它的实现方式,并且前段时间发现居然有些朋友和当时的我一样。
比如下面这个例子:
class Foobar {
Runnable foobar() {
return () -> {
};
}
}
在最初的时候,我猜想它也许会像这样实现:
class Foobar {
Runnable foobar() {
return new Runnable() {
@Override
public void run() {
return;
}
};
}
}
实际上,并不是。
当然了,如果真是这样做了也算是一种实现方式,但是Java这里做出了更加巧妙的设计。
这个函数在Java8中经过编译后的字节码是这样的:
java.lang.Runnable foobar();
descriptor: ()Ljava/lang/Runnable;
flags:
Code:
stack=1, locals=1, args_size=1
0: invokedynamic #2, 0 // InvokeDynamic #0:run:()Ljava/lang/Runnable;
5: areturn
LineNumberTable:
line 3: 0
乍一看似乎莫名其妙,run
方法其实也实现在了这个类里:
private static void lambda$foobar$0();
descriptor: ()V
flags: ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
Code:
stack=0, locals=0, args_size=0
0: return
LineNumberTable:
line 3: 0
它们通过InvokeDynamic
这个字节码指令以及一个BootstrapMethod才在两者之间建立起联系:
0: #16 invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
Method arguments:
#17 ()V
#18 invokestatic Foobar.lambda$foobar$0:()V
#17 ()V
看到这里的朋友,大概应该都是用过MethodHandle
的吧,不然的话上面这段可能不太好理解。
用Java代码大致模拟一下,运行时的逻辑大概像是这样:
class Foobar {
@SuppressWarnings("unchecked")
Runnable foobar() throws Throwable {
return (Runnable) LambdaMetafactory.metafactory(
MethodHandles.lookup(),
"run",
MethodType.methodType(Runnable.class),
MethodType.methodType(void.class),
MethodHandles.lookup().findStatic(Foobar.class, "lambda$foobar$0", MethodType.methodType(void.class)),
MethodType.