home

Exception Handling

Handle and Declare Pattern

void f() throws IOException {
    try {
        throw new IOException();
    } catch (Exception e) {  // Not really!
        throw e;             // Due to this guy here!
    }                        // Actually catching only types declared in method signature
}
// does not compile
void f() throws IOException {
    throw new Exception();
}

How This Feature Prevents Compilation Failures

Imagine the following scenario:

class A extends Exception {}
class B extends Exception {}

void foo() throws A, B {}

void bar() throws A, B {
    try {
        foo();
    } catch (A | B e) {
        throw e;
    }
}
void foo() throws A {}

void bar() throws A, B {     // B is never thrown, but it is legal to declare
    try {                    // At least compile does not fail just because foo removed throws B
        foo();
    } catch (Exception e) {  // Remember catch (A | B e) was causing a compilation error
        throw e;
    }
}

Exceptions in Inheriting Methods

class MyException extends Exception {}

class A {
    void a() throws MyException {};
}

class B extends A {
    public void a() {}  // no need for throws MyException
}
class A {
    void f() {}
}

class B extends A {
    void f() throws RuntimeException {}  // this is fine
                                         // throwing a CheckedException would not compile 
}

Calling Method Must Handle Exception Based on the Reference Type

A a = new B();
try {
    a.a();
} catch (MyException e) { // Must handle exception
    e.printStackTrace();  // Call is on type A not B
}
class MyException extends Exception {}

interface A {
    void a() throws MyException;
}

class B implements A {
    public void a() throws MyException {  // throws Exception will not compile!
        throw new MyException();
    }
}