单行 Lambda 和 运行 时间异常 - 不编译?

Single line Lambda and Run-time exceptions - Not compiling?

我正在处理单行 lambda 和 运行 时间异常。

我测试了以下用例,发现语句 1 未编译 where as 语句 2编译正常。

 new Thread(() -> throw new RuntimeException("test")); // 1
 new Thread(() -> new RuntimeException("test")); //2

请帮助我理解为什么语句 1 没有编译但语句 2 编译正常。

如果将第 1 行更改为:

,则会编译
new Thread(() -> { throw new RuntimeException("test"); });

大括号只能在单个语句中省略。

第二行是创建新 RuntimeException 的单个表达式,但除此之外没有其他效果。

Java Lambda Expressions Syntax Specification

我猜这是你想要的:

new Thread(() -> { throw new RuntimeException("test"); }); // 1

下面写成语句就好了:

new RuntimeException();

创建和抛出异常实例是不同的事情。因此,这没有任何用处;它只是让房间暖和了一点。

这正是您在第二种形式中所做的。

lambda 表达式定义(在 JLS 15.27. Lambda Expressions 中)为:

LambdaExpression:
LambdaParameters -> LambdaBody

LambdaBody 定义为:

LambdaBody:
Expression
Block

在你的两个 lambda 表达式中,你没有使用块作为 lambda 主体(这需要花括号),这意味着你必须使用表达式。

表达式定义为:

Expressions can be broadly categorized into one of the following syntactic forms:

  • Expression names (§6.5.6)

  • Primary expressions (§15.8 - §15.13)

  • Unary operator expressions (§15.14 - §15.16)

  • Binary operator expressions (§15.17 - §15.24, and §15.26)

  • Ternary operator expressions (§15.25)

  • Lambda expressions (§15.27)

new RuntimeException("test") 属于“主要表达式”类别,其中包括对象创建(创建的对象是 Exception 的事实没有区别)。因此它是一个有效的 lambda 主体。

另一方面,throw new RuntimeException("test") 不属于任何这些类别,因此不是表达式。

为了让 lambda 主体包含该语句,您必须使用 Block LambdaBody:

new Thread(() -> {throw new RuntimeException("test");});

lambda 表达式的基本语法是:

(parameters) -> expression

(parameters) -> {statements;}

在你的第一个语句中,throw new RuntimeException("test");是一个语句(更具体地说,是一个throw Statement),所以它应该用方括号括起来:

new Thread(() -> {throw new RuntimeException("test")}); 

在第二条语句中,new RuntimeException("test")是一个表达式,(更具体地说,是一个Class Instance Creation Expression)。这就是它在没有括号和分号的情况下工作的原因。

================一些额外的东西====================

此处,lambda 表达式() -> new RuntimeException("test")Runnable 接口一起使用,其 return 类型为 void。实际上,它也可以与 returning Exception 一起使用,例如:

  @FunctionalInterface interface ExceptionSupplier{Exception supply();} //another functional interface that it works with!

  ExceptionSupplier e = () -> new RuntimeException("test");
  System.out.println(e.supply()); //prints "java.lang.RuntimeException: test"

在这种情况下,完全相同的表达式被计算为

ExceptionSupplier e = () -> {return new RuntimeException("Test");};

这是因为表达式 () -> new RuntimeException("test")void-compatiblevalue-compatible(见 here)

A block lambda body is void-compatible if every return statement in the block has the form return;.

A block lambda body is value-compatible if it cannot complete normally (§14.21) and every return statement in the block has the form return Expression;.

这个答案的灵感来自@AndyTurner 和@Eran 的答案。 欢迎补充。