对于返回void的lambda,这是有效的:
Runnable b = () -> System.out.println("3");
但这不是:
Runnable b = () -> throw new RuntimeException("3");
我知道我可以将其放在大括号中,但是为什么这对于内联lambda无效?
答案 0 :(得分:2)
() -> foo
语法将lambda的主体定义为表达式(JLS 15.27.2),因此throw new RuntimeExpression("3")
不会编译是完全合理的:这是一条语句,而不是表达式。因此,真正的问题是,为什么println会编译?毕竟,这也是声明。
JLS 15.27.3表示:
如果函数类型的结果为void,则lambda主体为语句表达式(第14.8节)或与void兼容的块。
您的示例都不是块(void兼容或其他),因此它们必须是语句表达式。这些定义在JLS 14.8中,包括:
StatementExpression:
Assignment
PreIncrementExpression
PreDecrementExpression
PostIncrementExpression
PostDecrementExpression
MethodInvocation
ClassInstanceCreationExpression
请注意MethodInvocation-这就是让您的println lambda进行编译的原因。
因此,简而言之:第一个println之所以编译是因为它是语句表达式的MethodInvocation形式,而throw则不会编译,因为语句表达式不包含throw
。
请注意,所有语句表达式都是表达式(因此而得名),因此实际上可以归结为以下事实:尽管实际上我们只想到了println实际上是类型void
的表达式。作为声明。 (实际上,我们通常将其视为语句的原因是,您只能将其用作语句表达式,如JLS 15.1中所述)。