1

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 :)

Randa Sbeity
  • 370
  • 3
  • 10
  • The compiler doesn't handle such a situation. Can you say why you would write code that way? – Peter Lawrey Dec 05 '13 at 20:10
  • I'm actually not writing any code. I'm just learning some basics about checked and unchecked exceptions and how the compiler behaves and checks for exceptions. I thought about this situation and I figured to ask to see if someone has any idea. I will try to think of a real example but as you said it seems that the compiler doesn't handle such a case anyway. – Randa Sbeity Dec 05 '13 at 20:24

1 Answers1

1

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.

MadConan
  • 3,749
  • 1
  • 16
  • 27
  • but it compiles fine if you do catch(Exception e){c.m1();}finally{throw new NullPointerException();} – Randa Sbeity Dec 05 '13 at 20:31
  • 2
    That's because the compiler can see that a runtime exception will occur for sure. Even with the other class saying it throws one, that could change, which would change the decision for the finally block. – MadConan Dec 05 '13 at 20:34
  • 1
    RIGHT! which you made me think that c.m2() is not known to the compiler to be the actual m2() in TestClass bcz there's a possibility that at runtime 'c' will point to a different object that extends TestClass and that overrides m2() without having a throws clause in its declaration (which is valid and possible). It totally makes sense now, however I defined m2() as static final (to make sure to tell the compiler that there's no possible way for m2() to change at runtime) but I still get the same error. I guess Java overlooked this. maybe they will enhance the compiler check in later verison. – Randa Sbeity Dec 05 '13 at 21:23