I am compiling this class:
public class Test {
// No throws clause here
public static void main(String[] args) {
doThrow(new SQLException());
}
static void doThrow(Exception e) {
Test.<Exception>doThrow0(e);
Test.doThrow0(e);
}
static <E extends Exception> void doThrow0(Exception e) throws E {
throw (E) e;
}
}
Why **Test.<Exception>doThrow0(e);**
this line gives error to specify throws clause (or enclose it in try-catch )
And **Test.doThrow0(e);**
this line don't give any error to use throws clause
This is because type inference prefers inferring type parameters that appear in the throws
clause to unchecked exceptions whenever possible.
From JLS 18.1.3:
During the inference process, a set of bounds on inference variables is maintained. A bound has one of the following forms:
- ...
throws α
: The inference variable α appears in athrows
clause....
A bound of the form
throws α
is purely informational: it directs resolution to optimize the instantiation of α so that, if possible, it is not a checked exception type.
In the first attempt to resolution, this bound is taken into account.
Otherwise, if the bound set contains
throws αi
, and each proper upper bound of αi is a supertype ofRuntimeException
, then Ti =RuntimeException
.
In Test.doThrow0(e)
, there is nothing suggesting that E
should be a checked exception, so type inference infers it to be RuntimeException
, an unchecked exception.
If doThrow0
took an E
as parameter instead, that establishes a relationship between the type of the argument and the type of the exception doThrow0
throws. Now E
would be inferred to be Exception
in the call Test.doThrow0(e)
.
In Test<Exception>doThrow0(e)
, you explicitly specified that E
should be a checked exception. Type inference doesn't even get involved here.
See also this other question where you can find examples where this "try not to infer a checked exception" is desirable.