2

I am working on single line lambda and run time exceptions.

I have tested following use cases and found statement 1 is not compiling where as statement 2 is compiling fine.

 new Thread(() -> throw new RuntimeException("test")); // 1
 new Thread(() -> new RuntimeException("test")); //2

Please help me understand why statement 1 is not compiling but statement two is compiling fine.

T-Bag
  • 10,916
  • 3
  • 54
  • 118

5 Answers5

9

A lambda expression is defined (in JLS 15.27. Lambda Expressions ) as:

LambdaExpression:
LambdaParameters -> LambdaBody

A LambdaBody is defined as:

LambdaBody:
Expression
Block

In both your lambda expressions, you don't use a block as the lambda body (that would require curly braces), which means you must be using an Expression.

Expression is defined as:

Expressions can be broadly categorized into one of the following syntactic forms:

  • Expression names (§6.5.6)

  • Primary expressions (§15.8 - §15.13)

  • Unary operator expressions (§15.14 - §15.16)

  • Binary operator expressions (§15.17 - §15.24, and §15.26)

  • Ternary operator expressions (§15.25)

  • Lambda expressions (§15.27)

new RuntimeException("test") falls into the category of "Primary expressions", which includes object creations (the fact that the object being created is an Exception makes no difference). Therefore it's a valid lambda body.

On the other hand, throw new RuntimeException("test") doesn't fall into any of these categories, and therefore is not an expression.

In order for a lambda body to contain that statement, you must use a Block LambdaBody:

new Thread(() -> {throw new RuntimeException("test");});
Community
  • 1
  • 1
Eran
  • 387,369
  • 54
  • 702
  • 768
  • 2
    It might be worth pointing out the similarity between throw and return: you can't return in an email lambda body either, for the same reason. – Andy Turner Aug 01 '18 at 06:00
4

Line number 1 compiles if you change it to:

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

Curly braces can only be omitted for single statements.

The second line is a single expression which creates a new RuntimeException, but it has no effect apart from that.

See Java Lambda Expressions Syntax Specification

Alexander Egger
  • 5,132
  • 1
  • 28
  • 42
  • Why does the second expression work? According to the syntax it should be equal to `Runnable runnable = () -> {return new RuntimeException("test");}; new Thread(runnable);`, which doesn't compile. – justgivememyicecream Aug 01 '18 at 05:40
  • 3
    @justgivememyicecream no, it's not the same as that. There is no implicit return, in the same way as it is fine to write `() -> System.out.println("")` in a lambda. The key thing is that it is [void-compatible](https://docs.oracle.com/javase/specs/jls/se9/html/jls-15.html#jls-15.27.2). – Andy Turner Aug 01 '18 at 05:48
  • @AndyTurner thinks for pointing that out. Added this to my answer – Alexander Egger Aug 01 '18 at 05:57
2

It's fine to write the following as a statement:

new RuntimeException();

Creating and throwing the exception instance are separate things. As such, this does nothing useful; it just warms up the room a little bit.

This is exactly what you are doing in the second form.

Andy Turner
  • 137,514
  • 11
  • 162
  • 243
  • I don't think so...the OP's second expression did not have a ";". According to [the lambda syntax](https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html#syntax), "If you specify a single expression, then the Java runtime evaluates the expression and then returns its value. " – justgivememyicecream Aug 01 '18 at 05:46
  • Sorry, I tried running the code and the second thread indeed did not throw any exception. But why? – justgivememyicecream Aug 01 '18 at 05:47
  • 1
    @justgivememyicecream if you do that *in a lambda which has to return a value*. If the return type is void, it doesn't return a value. – Andy Turner Aug 01 '18 at 05:49
  • 1
    @justgivememyicecream "Creating and throwing the exception instance are separate things". – Andy Turner Aug 01 '18 at 05:53
  • Does that mean that the result of the evaluation of a lambda expression varies based on the functional interface's return type? For example, it also works when I have a `@FunctionalInterface interface ExceptionSupplier{Exception supply();}` and do `ExceptionSupplier e = () -> new RuntimeException("test");`, in which case the same expression `new RuntimeException("test")` is evaluated as an implicit return. – justgivememyicecream Aug 01 '18 at 06:02
  • 1
    @justgivememyicecream yes. – Andy Turner Aug 01 '18 at 06:03
0

I guess this what you want:

new Thread(() -> { throw new RuntimeException("test"); }); // 1
Nin
  • 375
  • 1
  • 11
0

The basic syntax of a lambda expression is:

(parameters) -> expression

or

(parameters) -> {statements;}

In your first statement, throw new RuntimeException("test"); is a statement (more specifically, a throw Statement), so it should be surrounded by brackets:

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

In the second statement, new RuntimeException("test") is an expression, (more specifically, a Class Instance Creation Expression). That's why it works without the brackets and the semicolon.

================A little something additional====================

Here, the lambda expression () -> new RuntimeException("test") works with the Runnable interface whose return type is void. Actually, it could also work with something returning an Exception, e.g.:

  @FunctionalInterface interface ExceptionSupplier{Exception supply();} //another functional interface that it works with!

  ExceptionSupplier e = () -> new RuntimeException("test");
  System.out.println(e.supply()); //prints "java.lang.RuntimeException: test"

In this case, the very same expression is evaluated as

ExceptionSupplier e = () -> {return new RuntimeException("Test");};

This is because the expression () -> new RuntimeException("test") is both void-compatible and value-compatible (see here)

A block lambda body is void-compatible if every return statement in the block has the form return;.

A block lambda body is value-compatible if it cannot complete normally (§14.21) and every return statement in the block has the form return Expression;.

This answer has been inspired by both @AndyTurner and @Eran's answers. Further complements are welcome.