为什么必须用lambda体中的完整代码块来包含throw语句?

时间:2017-04-09 14:38:38

标签: java exception lambda java-8

如果lambda函数中有一个语句,我们可以省略为它定义完整的代码块:

new Thread(() -> System.out.println());

为什么抛出异常的语句不是这种情况?这会产生一个编译错误,说明'{' expected

new Thread(() -> throw new RuntimeException());

当然,将lambda主体包含在代码块中可以起作用:

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

3 个答案:

答案 0 :(得分:24)

AFAIK jls表示lambda body必须是:

表达式。它是这样的:

new Thread(() -> throw new RuntimeException());

既不是,编译器以某种方式通知你。

声明如下:

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

使它成为一个块。以下是相关部分:

  

块是一系列语句,本地类声明和大括号内的局部变量声明语句

答案 1 :(得分:20)

在Java8中,lambda body的语法只接受expressionblock。鉴于throwing an exception语句,而非表达式

throwStatement: 'throw' expression ';' ;

lambdaBody: expression | block;

expression: lambdaExpression | assignmentExpression;

block : '{' blockStatements? '}' ;

如果需要,可以通过在下一个jdk版本中将throwStatement包含到lambdaBody中来增强它。实际上,正如你上面提到的,我们需要这样做例如:

lambdaBody: expression | block | throwStatement;

答案 2 :(得分:14)

throw语句是一个语句,而不是表达式,所以它必须放在大括号内。根据{{​​3}},Java专家组当时对lambdas的语法进行了非正式调查,有四种选择:

  • 稻草人#(arglist)(expr) and #(arglist){statements}
  • BGGA { args -> statements }(类似于Scala和Groovy)
  • SotL #{ args -> statements}
  • Redmond (args) -> { statements }

最终,选择是根据this article采用类似于C#的语法,就我所见,它看起来也与上面的最后一个选项最接近。在C#中,表达式lambdas 语句lambdas 之间存在区别:

表达式lambda(C#):

(input parameters) => expression

声明lambda(C#):

(input parameters) => {statement;}  

语法在this thread中解释。

在前一个主题中提到了在其他选项中选择此语法的基本原理:

  

选择此语法的决定是双重的:

     
      
  • 语法在大多数主观测量中得分“相当不错”(尽管如此)   有这样的情况,它看起来很糟糕,就像所有其他人一样)。在   特别是,它适用于作为方法使用的“小”lambda   参数(一个常见的情况),也适用于大型   (多语句)lambdas。

  •   
  • 尽管进行了广泛的搜索,但其中并没有明显的赢家   替代方案(每种形式都有一些好的方面,有些确实不是很好   好的方面,并没有明显优于   其他)。所以,我们觉得最好选择有的东西   已经证明在最喜欢的两种语言中效果很好   Java - C#和Scala - 而不是发明新东西。

  •