Card 05/ 10

WalkthroughDifficulty: Intermediate2 min

Following One Exception From the throw to the Handler

Four methods calling one another, a failure at the bottom, and a handler at the top. Watching the whole run is what makes a stack trace readable afterwards.

java
void main() {
    try {
        runReport();
    } catch (IOException e) {
        System.out.println("handled: " + e.getMessage());
    }
}

void runReport() throws IOException { collect(); }
void collect() throws IOException { read(); }
void read() throws IOException { throw new IOException("disk full"); }

What one throw does to four stack frames

Step 1 of 5

read throws

The exception object is created, and it captures the call stack as it stands right now — four frames deep. That capture is what a stack trace prints later, and it happens at new, not at the catch.

read has no handler, so its frame is discarded

There is no try in read, so nothing here can take it. The method does not return a value and does not run any further lines; its frame is removed and the exception continues upwards.

collect and runReport do the same

Both declared throws IOException, which is a promise to the compiler rather than an instruction to the runtime. Neither has a catch, so both frames are discarded in turn. Every line after the failing call in each of them is skipped.

main has a matching catch

text
handled: disk full

The catch type is IOException and the thrown object is one, so this handler takes it. The exception stops travelling and normal execution resumes at the first line inside the catch.

If nothing had matched

The exception would have left main, the thread would end, and the default handler would print the captured stack trace to standard error. That trace is the list of frames from step one, in the order they were discarded.

The useful consequence: the top line of a stack trace is where it was thrown and the bottom is where the program started. Reading from the top tells you what failed; reading down tells you what was being attempted.