ami*_*ahu 13 java lambda jvm final
我在 main 方法中执行如下:
int secrete = 42;
for (int i = 0; i < 5; i++) {
Consumer<String> myprinter2 =
msg -> {
System.out.println("consuming " + msg + " ," + secrete);
};
myprinter2.accept(myprinter2.toString());
}
Run Code Online (Sandbox Code Playgroud)
上述代码的输出是:
int secrete = 42;
for (int i = 0; i < 5; i++) {
Consumer<String> myprinter2 =
msg -> {
System.out.println("consuming " + msg + " ," + secrete);
};
myprinter2.accept(myprinter2.toString());
}
Run Code Online (Sandbox Code Playgroud)
如果我改为secretefinal,那么输出是:
consuming Main$$Lambda$1/1324119927@6d311334 ,42
consuming Main$$Lambda$1/1324119927@682a0b20 ,42
consuming Main$$Lambda$1/1324119927@3d075dc0 ,42
consuming Main$$Lambda$1/1324119927@214c265e ,42
consuming Main$$Lambda$1/1324119927@448139f0 ,42
Run Code Online (Sandbox Code Playgroud)
secrete即使我没有将其声明为最终,它实际上也是最终的,那么为什么当我没有将其声明为最终时,每个 lambda 都被视为一个新对象呢?
“有效最终”在技术上不是必需的,没有它也可以完成。但语言设计者设置此限制是为了避免混淆,因为如果变量不断变化,那么 lambda 会看到什么值,是初始值还是最新值?其他具有 lambda 的语言没有此限制,并且规范设置了此用例的期望。
给出以下代码:
import java.util.function.Consumer;
class Main {
public static void main(String args[]) {
int i = 42;
final int j = 41;
for (int k = 0; k < 5; k++) {
Consumer<String> x = msg -> System.out.printf("x=%s, i=%d%n", msg, i);
Consumer<String> y = msg -> System.out.printf("y=%s, j=%d%n", msg, j);
Consumer<String> z = msg -> System.out.printf("z=%s%n", msg);
x.accept(x.toString());
y.accept(y.toString());
z.accept(z.toString());
}
}
}
Run Code Online (Sandbox Code Playgroud)
当我们使用 检查生成的字节码时javap -c -v Main.class,我们会看到:
11: invokedynamic #7, 0 // InvokeDynamic #0:accept:(I)Ljava/util/function/Consumer;
16: astore_3
17: invokedynamic #11, 0 // InvokeDynamic #1:accept:()Ljava/util/function/Consumer;
22: astore 4
24: invokedynamic #14, 0 // InvokeDynamic #2:accept:()Ljava/util/function/Consumer;
Run Code Online (Sandbox Code Playgroud)
我们可以看到 lambda 是如何翻译的。相应的static方法表明,第一个 lambda 是捕获 lambda,并且在转换后具有整数第一个参数 (#71),而其他 lambda 则没有。
BootstrapMethods:
0: #63 REF_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:
#70 (Ljava/lang/Object;)V
#71 REF_invokeStatic Main.lambda$main$0:(ILjava/lang/String;)V
#74 (Ljava/lang/String;)V
1: #63 REF_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:
#70 (Ljava/lang/Object;)V
#75 REF_invokeStatic Main.lambda$main$1:(Ljava/lang/String;)V
#74 (Ljava/lang/String;)V
2: #63 REF_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:
#70 (Ljava/lang/Object;)V
#78 REF_invokeStatic Main.lambda$main$2:(Ljava/lang/String;)V
#74 (Ljava/lang/String;)V
Run Code Online (Sandbox Code Playgroud)
所以,这就是 lambda 的翻译方式。您可以在本文中找到更多详细信息。