Exceptions

exercises
tutorial
java
exceptions

Applied class exercises for week 5, tracing execution through nested try/catch/finally blocks — reinforcing java-exceptions. Uses this exception hierarchy throughout:

class E1 extends Exception {};
class E2 extends E1 {};
class E3 extends E1 {};
class E4 extends E3 {};
class E5 extends E3 {};

class F1 extends Exception {};
class F2 extends F1 {};
class F3 extends F1 {};
class F4 extends F1 {};

On the HTML site, fill in each blank with your answer (as a quoted string, in the form x, y, e.g. "12, 20"), then click Run Code to check it. In the PDF, the Working callout is shown as a static answer key instead (interactive checking needs a browser).

Question 1

x and y are member variables, both starting at 0:

public void exercise1() {
    try {
        try {
            f();
            y += 10;
        } catch (F3 e) {
            x += 1;
        } catch (F1 e) {
            x += 10;
        } catch (F4 e) {
            x += 100;
        } catch (E5 e) {
            y += 1;
            throw e;
        } finally {
            x += 2;
        }
        y += 20;
    } catch (Exception e) {
        y += 100;
    }
}

What are x, y after exercise1() is called, if f() throws each of the following?

f() throws F2

f() throws F3

f() throws F4

f() throws E4

f() throws E5

  • F2: not caught by the inner catch (F3), catch (F4), or catch (E5), but is an F1 (F2 extends F1) → caught by catch (F1 e): x += 10. finally always runs: x += 2x = 12. No exception escapes the inner try, so y += 20 still runs → y = 20.
  • F3: directly caught by catch (F3 e): x += 1. finally: x += 2x = 3. y += 20 runs → y = 20.
  • F4: matches catch (F1 e) before reaching catch (F4 e), since catch clauses are checked in order and F4 extends F1 — so it’s caught by the F1 handler: x += 10. finally: x += 2x = 12. y += 20 runs → y = 20.
  • E4: none of the inner catch clauses match (F3/F1/F4 are all F-hierarchy, E5 is a sibling of E4’s ancestor E3, not a match) — only finally runs (x += 2x = 2), then the exception propagates to the outer catch (Exception e): y += 100y = 100.
  • E5: matches catch (E5 e): y += 1, then re-throws it. finally still runs: x += 2x = 2. The re-thrown exception escapes the inner try entirely (skipping y += 20) and is caught by the outer catch (Exception e): y += 100y = 1 + 100 = 101.

Does exercise1 need a throws declaration? No — every exception f() might throw is either caught by the inner try or (for the re-thrown E5) by the outer try. A throws declaration is only needed for checked exceptions that escape uncaught.

Question 2 — bonus

public void exercise2() throws ... {
    try {
        y += g();
    } catch (E3 e) {
        x += 100;
    }
}

public int g() throws ... {
    try {
        f();
        y += 10;
        return 400;
    } catch (E1 e) {
        x += 1;
    } finally {
        x += 10;
    }
    return 1;
}

f() throws E1

f() throws E2

f() throws E3

Whichever of E1/E2/E3 is thrown, g()’s catch (E1 e) matches (all are E1 or subclasses), so x += 1, then finally runs x += 10x = 11g() never reaches return 400 or return 1 explicitly inside the catch, so it falls through to the final return 1. Back in exercise2, y += g() adds that 1 to yy = 1. The exception never escapes g(), so exercise2’s own catch (E3 e) never runs (x stays at 11, not 111).

The throws declarations on exercise2 and g would differ depending on which exception type f() actually throws (only checked exceptions that can escape uncaught need declaring).

Question 3 — bonus

g() throws F2 (unconditionally, when called):

public void exercise3() throws ... {
    try {
        try {
            try {
                f();
                x += 100;
            } catch (F2 e) {
                x += 5;
                g();
            } catch (F1 e) {
                x += 1;
            } catch (E1 e) {
                y += 2;
                throw e;
            }
            y += 10;
        } catch (F2 f) {
            y += 100;
        }
    } catch (Exception e) {
        x += 1000;
    }
}

f() throws F3

f() throws F2

f() throws E1

f() throws F1

  • F3: not caught by catch (F2 e), but is caught by catch (F1 e) (F3 extends F1): x += 1. No further exception, y += 10 runs. Neither outer catch triggers → x = 1, y = 10.
  • F2: caught directly by catch (F2 e): x += 5, then calls g(), which itself throws F2 — this propagates out of the innermost try (skipping y += 10) to the middle catch (F2 f): y += 100. → x = 5, y = 100.
  • E1: none of F2/F1 catch it, but catch (E1 e) does: y += 2, then re-throws. This isn’t an F2, so the middle catch (F2 f) doesn’t match — it propagates to the outermost catch (Exception e): x += 1000. → x = 1000, y = 2.
  • F1: caught by catch (F1 e) directly (an F1 isn’t an F2): x += 1. y += 10 runs. → x = 1, y = 10 (same result as F3, since both only match the F1 handler).