Search code examples
javaexceptionchecked-exceptions

Compilation error when calling generic method which throws generic exception


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


Solution

  • 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 a throws 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 of RuntimeException, 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.