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.
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");});
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.
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.
I guess this what you want:
new Thread(() -> { throw new RuntimeException("test"); }); // 1
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.
来源:https://stackoverflow.com/questions/51625883/single-line-lambda-and-run-time-exceptions-not-compiling