38

If there is a single statement in a lambda function, we can omit defining the full code block for it:

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

Why is that not the case for statements that throw exceptions? This yields a compilation error stating '{' expected:

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

Of course, enclosing the lambda body in a code block works:

new Thread(() -> {
    throw new RuntimeException();
});
Dragan Bozanovic
  • 23,102
  • 5
  • 43
  • 110
  • I'm not entirely sure, but i think omitting the block makes Java implicitly return the result of the expression. and a statement like `return System.out.println()` is valid, while `return throw new RuntimeException()` is not – Neutrosider Apr 09 '17 at 14:44
  • 3
    @Neutrosider A Runnable does not return anything, especially a void. – Jacob G. Apr 09 '17 at 14:56
  • 1
    Why do you think that a “canonical answer is required to address all the concerns”? What are the concerns that aren’t already addressed with Q&As like [this](https://stackoverflow.com/q/41961392) or [this](https://stackoverflow.com/q/11145696) or [this](https://stackoverflow.com/q/29262002) or [this](http://stackoverflow.com/q/41482574) or [this](https://stackoverflow.com/q/30584887) or [that](http://stackoverflow.com/q/24146285)? – Holger Apr 13 '17 at 15:23
  • 1
    @Holger Useful links, thanks, I wasn't able to find them myself though (especially the first one, which seems to be the exact duplicate). However, they also seem to lack the rationale behind the decisions made in the JLS, which I think would be helpful to understand the features better. The links to the discussion provided in the answer by manouti are also helpful I'd say. – Dragan Bozanovic Apr 13 '17 at 16:13

3 Answers3

25

AFAIK The jls says that the lambda body has to be:

expression or a block. Having it like this:

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

is neither and the compiler somehow informs you about that.

Declaring it like this:

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

makes it a block. Here is the relevant part:

A block is a sequence of statements, local class declarations, and local variable declaration statements within braces.

Eugene
  • 117,005
  • 15
  • 201
  • 306
  • Little confused about the up voting on this answer - the OP asks "why" the JLS is written this way. The OP did not give a hyperlink, this answer does, but this answer doesn't even posit a possible answer to 'why' and that was the question. – JoeG Apr 17 '17 at 19:02
  • 2
    @JoeG i did not expect so many upvotes myself, I admit. The OP is asking why this does not compile, not why the JLS was written like this, at least thats how Ive seen it after reading. – Eugene Apr 17 '17 at 19:12
  • @JoeG if the question was *why* the JLS was written like that, Holger provided the needed links for that. – Eugene Apr 17 '17 at 19:14
  • thanks - I believe you understood I meant no offense! I was just expecting an answer discussing Fork/Join thread pools and the requirement to catch any such thrown exceptions. In order to do achieve this, I believe the syntax was chosen, hence the compiler enforces.... – JoeG Apr 18 '17 at 10:50
21

In Java8, the grammar of a lambda body only accepts an expression or a block. Whereas throwing an exception is a statement, not an expression.

throwStatement: 'throw' expression ';' ;

lambdaBody: expression | block;

expression: lambdaExpression | assignmentExpression;

block : '{' blockStatements? '}' ;

Maybe it can be enhanced by including throwStatement into lambdaBody in the next jdk version if it is needed. Indeed, we need that as you mentioned above. for example:

lambdaBody: expression | block | throwStatement;
Andrew Tobilko
  • 48,120
  • 14
  • 91
  • 142
holi-java
  • 29,655
  • 7
  • 72
  • 83
15

A throw statement is, well, a statement and not an expression so it must be placed within braces. According to this article, the Java Expert Group had an informal survey on the syntax of lambdas at the time, and there were four options:

  • Strawman: #(arglist)(expr) and #(arglist){statements}
  • BGGA: { args -> statements } (similar to Scala and Groovy)
  • SotL: #{ args -> statements}
  • Redmond: (args) -> { statements }

Ultimately, the choice was to adopt a syntax similar to that of C# according to this thread, which also looks closest to the last option above as far as I can see. In C#, there is a distinction between expression lambdas and statement lambdas:

Expression lambda (C#):

(input parameters) => expression

Statement lambda (C#):

(input parameters) => {statement;}  

The syntax is explained in this MSDN documentation page.

And the rationale for choosing this syntax over the other options is mentioned in the previous thread:

The decision to choose this syntax was twofold:

  • The syntax scores "pretty well" on most subjective measures (though has cases where it looks bad, just like all the others do). In particular, it does well with "small" lambdas that are used as method arguments (a common case), and also does well with large (multi-statement) lambdas.

  • Despite extensive searching, there was no clear winner among the alternatives (each form had some good aspects and some really not very good aspects, and there was no form that was clearly better than the others). So, we felt that it was better to choose something that has already been shown to work well in the two languages that are most like Java -- C# and Scala -- rather than to invent something new.

M A
  • 71,713
  • 13
  • 134
  • 174