代码之家  ›  专栏  ›  技术社区  ›  flow2k

用于引发异常的内联lambda语法[重复]

  •  0
  • flow2k  · 技术社区  · 8 年前

    对于返回void的lambda,这是有效的:

    Runnable b = () -> System.out.println("3");
    

    但这不是:

    Runnable b = () -> throw new RuntimeException("3");
    

    我知道我可以把它放在一个带大括号的块中,但是为什么这对于内联lambda是无效的语法呢?

    1 回复  |  直到 8 年前
        1
  •  2
  •   yshavit    8 年前

    这个 () -> 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 ).