为什么java lambda表达式不会引入新的范围?

Tra*_*ity 8 java lambda expression function lambda-calculus

据我所知,在Haskell等语言中,以及作为lambda演算的一部分,每个lambda表达式都有自己的作用域,所以如果我有嵌套的lambda表达式,例如:\x -> (\x -> x)那么第一个\x参数与第二个参数不同\x.

在Java中,如果执行此操作,则会出现编译错误,就像您x再次使用作为参数名称或lambda中的局部变量名称一样,如果它已在封闭范围内使用,例如作为方法参数.

有没有人知道为什么Java以这种方式实现了lambda表达式 - 为什么不让它们引入一个新的作用域级别并且表现得像一个匿名类呢?我假设是因为某些限制或优化,或者可能是因为lambdas必须被黑客入侵现有语言?

Vam*_*ire 12

这与Java中的其他代码块的行为相同.

这给出了编译错误

int a;
{
    int a;
}
Run Code Online (Sandbox Code Playgroud)

虽然这不是

{
    int a;
}
{
    int a;
}
Run Code Online (Sandbox Code Playgroud)

您可以在JLS的第6.4节中阅读有关此主题的内容以及一些推理.


And*_*eas 5

lambda 块一个新块,也称为作用域,但它不会像匿名类实现那样建立新的上下文/级别。

\n

来自 Java 语言规范15.27.2 Lambda 主体

\n
\n

与出现在匿名类声明中的代码不同,出现在 lambda 主体中的名称和this和关键字的含义以及引用声明的可访问性与周围上下文中的相同(除了 lambda 参数引入了新名称)。super

\n
\n

来自 JLS 6.4 阴影和模糊

\n
\n

这些规则允许在变量或本地类范围内出现的嵌套类声明(本地类 ( \xc2\xa714.3 ) 和匿名类( \xc2\xa715.9 ))中重新声明变量或本地类。因此,形式参数、局部变量或局部类的声明可能会隐藏在嵌套在方法、构造函数或 lambda 表达式中的类声明中;并且异常参数的声明可能会隐藏在嵌套在 catch 子句的块中的类声明中。

\n

有两种设计替代方案可用于处理由 lambda 参数和 lambda 表达式中声明的其他变量创建的名称冲突。一是模仿类声明:与本地类一样,lambda 表达式为名称引入了新的“级别”,并且表达式之外的所有变量名称都可以重新声明。另一种是“本地”策略:与 catch 子句、for 循环和块一样,lambda 表达式在与封闭上下文相同的“级别”上运行,并且表达式外部的本地变量不能被隐藏。以上规则均使用本地策略;没有特殊的豁免允许 lambda 表达式中声明的变量隐藏在封闭方法中声明的变量。

\n
\n

例子:

\n
class Test {\n    private int f;\n    public void test() {\n        int a;\n        a = this.f;     // VALID\n        {\n            int a;      // ERROR: Duplicate local variable a\n            a = this.f; // VALID\n        }\n        Runnable r1 = new Runnable() {\n            @Override\n            public void run() {\n                int a;           // VALID (new context)\n                a = this.f;      // ERROR: f cannot be resolved or is not a field\n                                 //   (this refers to the instance of Runnable)\n                a = Test.this.f; // VALID\n            }\n        };\n        Runnable r2 = () -> {\n            int a;      // ERROR: Lambda expression\'s local variable a cannot redeclare another local variable defined in an enclosing scope.\n            a = this.f; // VALID\n        };\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n