【发布时间】:2016-11-21 09:27:04
【问题描述】:
考虑Lambda Expressions 中给出的以下代码:
import java.util.function.Consumer;
public class LambdaScopeTest {
public int x = 0;
class FirstLevel {
public int x = 1;
void methodInFirstLevel(int x) {
// The following statement causes the compiler to generate
// the error "local variables referenced from a lambda expression
// must be final or effectively final" in statement A:
//
// x = 99;
Consumer<Integer> myConsumer = (y) ->
{
System.out.println("x = " + x); // Statement A
System.out.println("y = " + y);
System.out.println("this.x = " + this.x);
System.out.println("LambdaScopeTest.this.x = " +
LambdaScopeTest.this.x);
};
myConsumer.accept(x);
}
}
public static void main(String... args) {
LambdaScopeTest st = new LambdaScopeTest();
LambdaScopeTest.FirstLevel fl = st.new FirstLevel();
fl.methodInFirstLevel(23);
}
}
在 JavaDocs 中写道:
假设您立即添加以下赋值语句 在
methodInFirstLevel定义语句之后:void methodInFirstLevel(int x) { x = 99; // ... }由于这个赋值语句,变量
FirstLevel.x不再是有效的final。结果,Java 编译器生成类似于“局部变量”的错误消息 从 lambda 表达式引用必须是最终的或有效的 final”,其中 lambda 表达式 myConsumer 尝试访问FirstLevel.x变量:
System.out.println("x = " + x);
我无法理解 System.out.println("x = " + x)(语句 A)如何访问 FirstLevel.x?不应该是methodInFirstLevel(int x)方法中传入的x吗?
【问题讨论】:
-
我认为这意味着 lambda 表达式无法访问
x中的x参数,因为它实际上不是最终的。它的措辞可能令人困惑(或实际上是错误的)。 -
编译器不知道,你在
myConsumer.accept(x);做什么,所以它假设x可以在这个方法中改变,如果是它就不能是最终的。这就是你得到错误的原因。 -
@TEXHIK,由于 Java 是按值传递的,
myConsumer不能更改x。这不是问题。 -
这似乎是教程中的错误。更有意义的是它说“由于这个赋值语句,参数
x不再是有效的最终参数。 ”