17

In Java (using Java 8 currently), I can write this and all will compile nice and well:

Supplier<Long> asd = () -> {
    throw new RuntimeException();
};

Yet, I cannot write this:

Supplier<Long> asd = () -> throw new RuntimeException(); // This won't compile :(

Does anyone know why Java's implementation does not allow such style (expression lambda) and only the statement/code-block style lambda?

I mean, since the lambda is only throwing the RuntimeException, why isn't the JDK able to infer the lambda expression as:

new Supplier<Long>() {
    @Override
    public Long get() {
        throw new RuntimeException();
    }
};

Is this documented somewhere in the specs/docs? Is this added only in JDK > 8?

Jesse
  • 3,522
  • 6
  • 25
  • 40
Tamir Nauman
  • 279
  • 1
  • 4
  • If I am not mistaken, the `{}` surrounding your statement `throw new RuntimeException()` is an "anonymous function". my guess is that the devs decided that all calls should be in a method, and not in the style you are asking for. this is in no way authoritative, hence the comment, rather than an answer... – JoSSte Nov 30 '18 at 12:45
  • 9
    You can not use the expression syntax, because a `throw` statement is not an expression. As simple as that. – Holger Nov 30 '18 at 12:48
  • 3
    because throw is not an expression in the same way as return is not an expression perhaps? – Joakim Danielson Nov 30 '18 at 12:49
  • 1
    Note: [C# got *throw expressions* in version 7](https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-7#throw-expressions). It might be a good idea to propose such a feature for Java as well (especially if Java ever gets a null coalescing operator, because that seems to be the main use case for throw expressions in C#). – Heinzi Nov 30 '18 at 15:31

2 Answers2

23

From the language spec JLS 15.27.2:

A lambda body is either a single expression or a block (§14.2). 

throw is not a single expression (it's a statement); so you have to use it in a block.

Andy Turner
  • 137,514
  • 11
  • 162
  • 243
18

What you wrote is an invalid lambda. There is a difference between the expression with the brackets {} and without. See the example. The following means that 1L is returned.

Supplier<Long> asd = () -> 1L;

which is equivalent to:

Supplier<Long> asd = () -> {
    return 1L;
}; 

However, when you write:

Supplier<Long> asd = () -> throw new RuntimeException();

It would be translated following which is an invalid lambda:

Supplier<Long> asd = () -> {
     return throw new RuntimeException();                    // invalid expression in Java
};

In a nutshell, you can understand () -> 1L as a shortcut for { return 1L; }.

Nikolas Charalambidis
  • 40,893
  • 16
  • 117
  • 183
  • 1
    This is not entirely the case, since the following program is valid: `Consumer consumer = str -> System.out.println(str)`. This is not elaborated to `Consumer consumer = str -> { return System.out.println(str); }` (which would similarly be an invalid program). Some special rules were added to accommodate expressions of type `void`; it's just that these same rules weren't added to accommodate `throw` statements. – Nick Dec 04 '18 at 02:16