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).