Java Optional.orElseThrow signature explanation

8.7k Views Asked by At

I looked at the Optional class method orElseThrow out of curiosity and I got confused of its signature. I didn't understand why it has to be declared as it is. So, I did an experiment with a copy of the original orElseThrow method and my simplified variant:

public class Main<T> {

    //This is original signature of Optional.orElseThrow method 
    public  <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X{

            throw exceptionSupplier.get();
    }

    //This is my attempt to simplify it but it doesn't work without try-catch block
    public T orElseThrow2(Supplier<Throwable> exceptionSupplier) throws Throwable{

        throw exceptionSupplier.get();
    }

    public static void main(String[] args){
        Main<Object> m = new Main<Object>();

            m.orElseThrow(() -> new RuntimeException("ha")); //no warnings/errors shown

            m.orElseThrow2(() -> new RuntimeException("sad")); //"Unhandled exception: java.lang.Throwable"
}
  1. Why my method is not accepted without a try-catch block?

  2. Why extending Throwable as in the original method doesn't require a try-catch block even though original method throws a Throwable object?

2

There are 2 best solutions below

1
On BEST ANSWER
  1. Because all the compiler knows about your method is that is throws a Throwable. Since the Throwable could thus be a checked exception, you're forced to declare it in the throws clause or to catch it.

  2. Because the compiler knows that the method throws X, where the generic type X is inferred as RuntimeException: () -> new RuntimeException("ha") is a Supplier<RuntimeException>. And runtime exceptions, by definition, are unchecked exceptions that don't need to be declared in the throws clause.

0
On

To clarify one step further:

Having a generic exception (throws X) is giving flexibility.

If you return a checked exception while using the first signature:

m.orElseThrow(() -> new Exception("ha"));

The compiler gives the error (Unhandled Exception) as well because it knows that some checked exceptions might be thrown. However, supplying RuntimeException gives the sign to the compiler that it is an unchecked exception.

On the other hand, in your custom method, you are making sure that it will always throw Throwable, which requires handling.