Search code examples
javafunctional-interface

Correct use of lambda expression with Optional#orElseThrow


Consider the following simple example:

Optional.empty().orElseThrow(this::exceptionSupplier);

IntelliJ generates a method like the following for the supplier, tough it does not compile!

private <X extends Throwable> X exceptionSupplier() {
    return new RuntimeException();
}

Incompatible types. Required: X Found: java.lang.RuntimeException

If i change the signature to the following it works.

private Exception exceptionSupplier() {
    return new RuntimeException();
}

Is it correct that the compiler cannot determine the correct type for X?


Solution

  • If the first example were to work, consider the following:

    Supplier<InterruptedException> s = this::exceptionSupplier;
    

    This would then fail with a ClassCastException if you called it like so:

    InterruptedException e = s.get();
    

    This is because X is determined at the call site. There is an implicit cast inserted by the compiler:

    InterruptedException e = (InterruptedException) s.get();
    

    But, of course, s returns you a RuntimeException, which can't be cast to InterruptedException.

    If you want to return a RuntimeException, make the return type of the method RuntimeException, no type variable required.