Skip to content

JEP 323: Local-Variable Syntax for Lambda Parameters | Lambda 参数的局部变量语法

摘要

允许在声明隐式类型 lambda 表达式的形式参数时使用 var

目标

  • 使隐式类型 lambda 表达式中形式参数的声明语法与局部变量声明的语法保持一致。

非目标

  • 使任何其他类型的变量声明(例如方法的形式参数)的语法与局部变量声明的语法保持一致。

动机

Lambda 表达式 可能是 隐式类型 的,即所有形式参数的类型都是推断出来的:

java
(x, y) -> x.process(y)    // 隐式类型 lambda 表达式

Java SE 10 使局部变量支持隐式类型:

java
var x = new Foo();
for (var x : xs) { ... }
try (var x = ...) { ... } catch ...

为了与局部变量保持一致,我们希望在隐式类型 lambda 表达式的形式参数中使用 var

java
(var x, var y) -> x.process(y)   // 隐式类型 lambda 表达式

统一性的一个好处是,修饰符(特别是注解)可以应用于局部变量和 lambda 形式参数,同时不失去简洁性:

java
@Nonnull var x = new Foo();
(@Nonnull var x, @Nullable var y) -> x.process(y)

描述

对于隐式类型 lambda 表达式的形式参数,允许使用保留类型名称 var,使得:

java
(var x, var y) -> x.process(y)

等价于:

java
(x, y) -> x.process(y)

隐式类型 lambda 表达式必须对所有形式参数都使用 var,或者一个都不用。此外,var 仅允许用于隐式类型 lambda 表达式的形式参数——显式类型 lambda 表达式继续为所有形式参数指定明确类型,因此不允许一些形式参数有明确类型而其他使用 var。以下示例是非法的:

java
(var x, y) -> x.process(y)         // 隐式类型 lambda 表达式中不能混用 'var' 和 '无 var'
(var x, int y) -> x.process(y)     // 显式类型 lambda 表达式中不能混用 'var' 和 明确类型

从理论上讲,可以有像上面最后一行那样的 lambda 表达式,它是半显式类型(或半隐式类型,取决于你的观点)。但是,这超出了本 JEP 的范围,因为它深刻影响了类型推断和重载解析。这是保持 lambda 表达式必须指定所有明确参数类型或都不指定的限制的主要原因。我们还希望确保隐式类型 lambda 表达式的参数推断出的类型,在使用 var 或不使用时保持一致。我们可能会在将来的 JEP 中回到部分推断的问题。此外,我们不想损害简写语法的简洁性,因此不允许类似以下表达式:

java
var x -> x.foo()

替代方案

继续像 Java SE 8 那样声明隐式类型 lambda 表达式。

风险与假设

在隐式类型 lambda 表达式中的参数名前添加 var 时,这个 JEP 不会产生源代码不兼容的风险,因为不带 var 的参数推断出的类型与带 var 的参数推断出的类型相同。