1

For a lambda that returns void, this is valid:

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

But this is not:

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

I know I can put it in a block with braces, but why is this not valid syntax for an inline lambda?

flow2k
  • 3,999
  • 40
  • 55
  • 1
    This seems very similar to [this question](https://stackoverflow.com/questions/51625883/single-line-lambda-and-run-time-exceptions-not-compiling) – Eran Aug 05 '18 at 06:19

1 Answers1

2

The () -> foo syntax defines the lambda's body as an expression (JLS 15.27.2), so it makes perfect sense that throw new RuntimeExpression("3") wouldn't compile: that's a statement, not an expression. So the real question is, why does the println compile? After all, that's a statement, too.

JLS 15.27.3 says that:

If the function type's result is void, the lambda body is either a statement expression (§14.8) or a void-compatible block.

Neither of your examples are blocks (void-compatible or otherwise), so they have to be statement expressions. Those are defined in JLS 14.8 and include:

StatementExpression:
  Assignment 
  PreIncrementExpression 
  PreDecrementExpression 
  PostIncrementExpression 
  PostDecrementExpression 
  MethodInvocation 
  ClassInstanceCreationExpression

Note the MethodInvocation -- that's what lets your println lambda compile.

So in short: The first println compiles because it's a MethodInvocation form of a statement expression, and the throw does not compile because statement expressions do not include throw.

Note that all statement expressions are expressions (hence the name), so what this really boils down to is the fact that the println is actually an expression of type void, despite the fact that we only ever think of it as a statement. (In fact, the reason we normally think of it as a statement is that you can only ever use it as a statement expression, as mentioned in JLS 15.1).

yshavit
  • 42,327
  • 7
  • 87
  • 124