Consider the following code:
public class Main {
public static void main(String[] args)
// throws Exception // line 1
{
Optional empty1 = Optional.empty(); // line 2
Optional<Object> empty2 = Optional.empty(); // line 3
Optional.empty().orElseThrow(() -> new Exception("Empty optional")); // line 4
empty1.orElseThrow(() -> new Exception("Empty optional")); // line 5
empty2.orElseThrow(() -> new Exception("Empty optional")); // line 6
}
}
When line 1 is commented, then line 4, 5, 6 all report compile-time errors:
- Line 4 and 6: Unhandled exception: java.lang.Exception
- Line 5: Unhandled exception: java.lang.Throwable
This makes me feel that line 4 is called with type parameter as
<Object>like line 6, but what makes the differences on the exact exception thrown?
When line 1 is uncommented, then only line 5 reports compile-time error: Unhandled exception: java.lang.Throwable. It will be solved if I change line 1 to throws Throwable. Why throwing Exception is not enough for line 5 to resolve compile-time error?
The difference is due to the use of raw types in Java. Method signature of orElseThrow is:
So, for case in line 2 and 5 you have:
in above
orElseThrowsignature case compiler is not provided withTtype and even thought it hasX, it will generate raw call. It will substitute X with its upperbound which is Throwable, and T will be Object. The result is:thus, compiler reports:
The case of:
is more interesting, here no explicit type is specified, but compiler reports error of
Exceptionbeing thrown. So its different from the previous case. You again must look at the signature of the used function, in this case Optional.empty():The important part is
<T>which indicate that it will infer its typeTfrom the enclosing context. Inline 4compiler is unable to infer type, and usesObjecttype instead. I believe in JLS its stated here:https://docs.oracle.com/javase/specs/jls/se10/html/jls-18.html#jls-18.1.3
and also in oracle tutorial:
https://docs.oracle.com/javase/tutorial/java/generics/genTypeInference.html
The important thing, is that in
line 4you are not dealing with raw types like in lines 2 and 5, but with generic ones (generic typeTisObject), so when orElseThrow is called, its signature isboth generic types
TnadXare known, so generic function call is generated, which in the end causes in your example this compiler error:error: unreported exception Exception;
Now, line 3 and 6, is explicitly using generic type Object, and this makes the signature of orElseThrow as previously:
which gives the same error:
error: unreported exception Exception;