【发布时间】:2018-05-25 12:32:14
【问题描述】:
我不明白为什么 java 语言的实现者会这样做,以便在 lambda 中使用并从函数范围传递的变量必须是最终的。
我反编译了这段代码:
public class Main {
@FunctionalInterface
interface Test {
void method(int t);
}
static void test(Test t) {
t.method(3);
}
public static void main(String... args) {
int a = 3;
test((i)-> {
System.out.println(a + i);
});
}
}
编译器所做的就是复制该变量,就好像它是通过构造函数传递的一样。我有这 3 个课程:
1:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
import Main.1;
import Main.Test;
public class Main {
public Main() {
}
static void test(Test var0) {
var0.method(3);
}
public static void main(String... var0) {
byte var1 = 3;
test(new 1(var1));
}
}
2:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
import Main.Test;
final class Main$1 implements Test {
Main$1(int var1) {
this.val$a = var1;
}
public void method(int var1) {
System.out.println(this.val$a + var1);
}
}
3:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
@FunctionalInterface
interface Main$Test {
void method(int var1);
}
为什么实现者不能只复制变量而不管它是否被修改,所以我们可以这样做:
public class Main {
@FunctionalInterface
interface Test {
void method(int t);
}
static void test(Test t) {
t.method(3);
}
public static void main(String... args) {
int a = 3;
test((i)-> {
a += 1; // allow modification, a is copied anyway, why not?
System.out.println(a + i);
});
}
}
【问题讨论】:
-
原因是为了简化代码,防止并发的复杂性。您声明了一个在 lambda 中使用的值,该值可以随时执行,难以遵循,因此强制它为 final 是一个不错的选择。这并不新鲜,顺便说一下,匿名内部类已经是这种情况了。实际上 final 只是一个语法糖(我认为没有必要),因为它的风格最终需要是 final 的。因此,将其声明为 final 并防止更新期间出现任何复杂情况会更简单。