Compile-Time Checking of Exceptions. Case where finally block is throwing unchecked exception implicitly

4.5k views Asked by At

The following code compiles perfectly. And I believe it's because the compiler knows at compile time that the control will go to the finally block and throw the unchecked exception (which is okay and doesn't require to be handled) and it knows that all other exceptions thrown by the code prior to this point are lost. so no need to worry abt them.

try{
     // DoSomething();
}catch(Exception e){ 
     // Throw checked exception
}finally{
    // Throw unchecked exception
}

example:

public class TestClass {
public static void main(String[] args) {
    TestClass c = new TestClass();
    try {
        // Whatever
    } catch (Exception e) {
        throw new FileNotFoundException(); 
    } finally {
        throw new NullPointerException();
    }
}
}

so far so good until I throw the unchecked exception from a method.

try{
     // DoSomething();
}catch(Exception e){ 
     // Call a method that throws a checked exception
     // or just throw the checked exception from here

}Finally{
    // Call a method that throw an unchecked exception
}

example:

public class TestClass {
public static void main(String[] args) {
    TestClass c = new TestClass();
    try {
        //Whatever
    } catch (Exception e) {
         c.m1(); 
             // or just throw it here
             // throw new FileNotFoundException();
    } finally {
        c.m2();
    }
}

public void m1() throws IOException {
    throw new FileNotFoundException();
}

public void m2() throws RuntimeException {
    throw new NullPointerException();
}
}

This code will not compile. It marks c.m1() with an error "Unhandled exception type _ " (eclipse) or "unreported exception _; must be caught or declared to be thrown" (cmd).

It's like it ignored that the finally block will throw the LAST exception (which is unchecked) and no need to worry about the one in the catch block even if it was an unhandled checked exception because they are going to be lost anyway! Knowing that m2() is DECLARED to throw specifically an unchecked exception (RuntimeException).

Does anyone have a better explanation about why there's a compilation error in the second code? Thanks :)

1

There are 1 answers

3
MadConan On BEST ANSWER

Exceptions just don't "throw" themselves. You must explicitly handle any checked exception thrown by a called method -- no matter where they occur. Anything you call that throws a checked exception must either be surrounded by a try catch block, or the method that is calling the sub-method must declare to throw the same type of exception. This does not apply to checked exceptions.

This means, that where you have

catch (Exception e) {
     c.m1(); 
         // or just throw it here
         // throw new FileNotFoundException();
}

you must catch the checked exception thrown by m1 because main does not declare that it throws anything.

With the finally block on the try/catch, you still must handle any checked exception thrown by a called method -- even in the catch block. But in the case where you explicitly throw the checked exception with a finally block that explicitly throws a runtime exception, the compiler allows it because it knows for sure what the sequence of events will be -- in any case at any time.