为什么java lambda表达式不会引入新的范围级别?
据我所知,在语言如Haskell中,并且也可作为演算的一部分,每个拉姆达表达式都有自己的范围,因此,如果我有嵌套lambda表达式如:\x -> (\x -> x)
则第一\x
参数是到所述第二不同\x
。为什么java lambda表达式不会引入新的范围级别?
在Java中,如果你这样做,你会得到一个编译错误,就像你再次使用x
作为参数名称或者lambda中的一个局部变量名,如果它已经在封闭范围内使用的话。作为方法参数。
有谁知道为什么Java实现的lambda表达式这种方式 - 为什么不把他们介绍的范围内一个新的水平和表现得像一个匿名类会吗?我假设这是因为一些限制或优化,或者可能是因为lambda必须被黑入现有语言?
这与Java中其他代码块的行为相同。
这给出了一个编译错误
int a;
{
int a;
}
虽然这并不
{
int a;
}
{
int a;
}
你可以阅读有关此主题的section 6.4 of the JLS,具有一定的推理在一起。
一个lambda块是一个新的块,又名作用域,但它并没有像匿名类实现那样建立新的上下文/级别。
从Java语言规范15.27.2 Lambda Body:
与出现在匿名类声明的代码,名称的含义,并出现在拉姆达身体,用引用声明的无障碍沿
this
和super
关键字,是与周围环境相同(除了lambda参数引入新名称)。
而且从JLS 6.4 Shadowing and Obscuring:
这些规则允许在嵌套类声明(局部类(§14.3)和匿名类可变或局部类的重声明(§15.9 ))发生在变量或本地类的范围内。因此,形式参数,局部变量或局部类的声明可以嵌套在嵌套在方法,构造函数或lambda表达式中的类声明中;并且可以在嵌套在catch子句的Block内的类声明中隐藏异常参数的声明。
有两种设计方案可用于处理由lambda参数和lambda表达式中声明的其他变量创建的名称冲突。一种是模仿类声明:就像本地类一样,lambda表达式为名称引入一个新的“级别”,并且可以重新声明表达式外的所有变量名称。另一个是“本地”策略:与catch子句,for循环和块一样,lambda表达式与封闭上下文在相同的“级别”下运行,并且表达式之外的局部变量不能被映射。 以上规则使用本地策略;没有特殊的配置允许在lambda表达式中声明的变量映射在封闭方法中声明的变量。
例子:
class Test {
private int f;
public void test() {
int a;
a = this.f; // VALID
{
int a; // ERROR: Duplicate local variable a
a = this.f; // VALID
}
Runnable r1 = new Runnable() {
@Override
public void run() {
int a; // VALID (new context)
a = this.f; // ERROR: f cannot be resolved or is not a field
// (this refers to the instance of Runnable)
a = Test.this.f; // VALID
}
};
Runnable r2 =() -> {
int a; // ERROR: Lambda expression's local variable a cannot redeclare another local variable defined in an enclosing scope.
a = this.f; // VALID
};
}
}
那么他们为什么做出这个决定,是有没有限制,这意味着他们不能,或者他们没有这样做的好处,即没有每个lambda的新的范围水平? – Tranquility
你如何参考外X在这样的语言中嵌套拉姆达内? –
@SotiriosDelimanolis你不一定要能够做到这一点,这是一个设计决定。你可以e。 G。也不能从一个匿名类访问局部变量x,在那里定义另一个非常有效的x。 – Vampire
[Variable已经在方法lambda中定义]的可能重复(https://stackoverflow.com/questions/22773003/variable-is-already-defined-in-method-lambda) – ZhekaKozlov