Eddie Lin
Eddie Lin

Reputation: 310

Why can the body of a lambda expression be composed of only a throws statement?

I have this code:

public class Sample {
  public static void useCallable(Callable<Integer> expression){}

  public static void main(String[] args){
    useCallable(()->{throw new IOException();});
  }
}

which compiles and runs fine.

However, shouldn't Callable<Integer> take nothing as input and return an Integer?

()->{throw new IOException();} doesn't return anything, so why is it a valid Callable<Integer> expression?

Upvotes: 1

Views: 93

Answers (1)

shmosel
shmosel

Reputation: 50716

For the same reason this method compiles:

Integer foo() throws Exception {
    throw new IOException();
}

Which compiles for the same reason as this method:

Integer foo() throws Exception {
    if (hasFoo()) {
        return getFoo();
    } else {
        throw new IOException();
    }
}

To quote the JLS,

If a method is declared to have a return type (§8.4.5), then a compile-time error occurs if the body of the method can complete normally (§14.1).

What does "complete normally" mean? According to the JLS (emphasis mine),

If all the steps are carried out as described, with no indication of abrupt completion, the statement is said to complete normally. However, certain events may prevent a statement from completing normally:

  • The break (§14.15), continue (§14.16), and return (§14.17) statements cause a transfer of control that may prevent normal completion of statements that contain them.

  • Evaluation of certain expressions may throw exceptions from the Java Virtual Machine (§15.6). An explicit throw (§14.18) statement also results in an exception. An exception causes a transfer of control that may prevent normal completion of statements.

In other words, a method with a return type must either return or throw. Yours does the latter, so it's valid.

Upvotes: 4

Related Questions