Concepts / Using try..catch to Handle Exceptions

Using try..catch to Handle Exceptions

A thrown exception is an object carrying the call stack and an error message from the failure point to the handler.

  • Programming
Interactive lab

Try it: try / except / else / finally

How an exception jumps out of a try block to the first matching except clause, when else runs, and why finally always runs.

How it works

  1. Statements in try run until one raises an exception; the rest of try is skipped.
  2. Python checks the except clauses in order and runs the first one whose type matches.
  3. If nothing was raised, the else block runs instead.
  4. finally runs in every case.

Default run (9 steps): Call safe_divide('4'). … Return 25.0. Output was: Worked: 25.0 / Done.

Simplified: One fixed function; int() and / are modelled exactly (including how Python prints floats), but nothing is executed as Python.

Educational simulation

Loading the simulation…

The Catch-All Plan and Why It Tempts Beginners

Many beginners arrive at exception handling with a simple plan. They wrap risky code in a try..catch, catch every possible error, and assume the program will never crash again. The goal is understandable, because a crashing program feels like a failure. This article examines that belief before it takes hold, because the Java class hierarchy for exceptions shows why it is mistaken.

The organization of the exception classes is not an accident of naming. It reflects a deliberate distinction between problems a program can reasonably respond to and problems it cannot. Once you can see that distinction, the question changes from how do I catch everything to which problems should my program handle, and which should it let stop the run.

What an Exception Object Carries

When something goes wrong at runtime, the item that is thrown is an object, not a bare error code or a plain message string. That object is an instance of a class in the family rooted at java.lang.Throwable. Every exception object must be an instance of some subclass of Throwable, and each distinct kind of problem usually has its own subclass.

Because the exception is an object, it can carry information. The source identifies two pieces that matter most. The first is the subroutine call stack, which is a list of the subroutines that were active when the exception was thrown. This list is always included. Because one subroutine can call another, several subroutines may be active at once, and the call stack records that chain. The second is an error message describing what caused the exception. The object can also hold other data, which is why an exception is more than a simple signal that something failed.

The useful consequence is that the exception object acts as a carrier. It moves information from the place where the failure happened to the place where the program decides what to do about it. The handler at the far end of that trip can read the message and the call stack instead of guessing what went wrong.

mainstarted first, still activeprocessOrdercalled by main, stillactiveparseQuantityexception thrown herecatch block in mainhandler that receives theobjectcallscallsexception travels upexception travels upexception stops here
When an exception is thrown deep inside nested method calls, how does it move back up the call stack, and where does it stop?

The diagram shows a chain of three active calls. The exception object is created where the failure happens, inside parseQuantity. It does not stay there. As the chain unwinds, it passes back up through processOrder, which is the subroutine that called it. It stops at the first place in the chain where a matching handler exists. Without a handler, it travels all the way out and the program stops. The call stack the object carries records this chain, so the handler can see the path the failure took.

Tracing a Thrown Exception Through try..catch

A try..catch statement divides code into two parts. The try block holds the statements that might fail. The catch block holds the response to one kind of exception. The example below is an original illustration written for this article. It is not a quotation from the source. Before you read the output, decide what you expect the program to print after the failure.

java
Output
Could not read quantity: For input string: "abc"
Program continues.
Notes on the code
  • The try block contains the statement that can fail.
  • Integer.parseInt throws an exception object because the text abc is not a number.
  • The catch block names the exception class it handles and receives the object as e.
  • e.getMessage() reads the error message carried by the exception object.
  • The statement after the try..catch runs because the handler dealt with the failure.

What do you think happens?

After the exception is thrown inside the try block, does the line that prints Program continues. still run?

  • Yes, because the catch block handled the exception

  • No, because the program stops at the failure

Reveal answer
Answer:

Yes, because the catch block handled the exception

The exception is caught, so control leaves the try..catch and continues with the next statement after it. The program does not stop.

Enter try blockParse the textstatement that failsException thrownfailure occurs hereRest of try skippedprint of quantity neverrunscatch block runsprints the error messageStatements after tryprogram continuesrunsfailscontrol jumpsmatching handlerhandled
After an exception is thrown inside a try block, which statements are skipped, which catch block runs, and what executes afterward?
Worked example

Following the failure in the QuantityReader example

Trace which statements run and which are skipped when the input is abc.

  1. 1
    Set the input

    input holds the text abc, which cannot be converted to an integer.

  2. 2
    Enter the try block

    The program begins the statements that might fail.

  3. 3
    Attempt the conversion

    Integer.parseInt(input) fails, and an exception object is created that carries the call stack and an error message.

  4. 4
    Skip the remaining try statements

    The line that assigns quantity and the line that prints Quantity: never run.

  5. 5
    Run the matching catch block

    The catch block for NumberFormatException receives the object as e and prints its message.

  6. 6
    Continue after the statement

    The try..catch is finished, so the final line prints Program continues.

Result

Two lines are printed: Could not read quantity: For input string: "abc" followed by Program continues.

The Throwable Family Tree

The classes that represent exceptions form a tree with Throwable at the root. Throwable has exactly two direct subclasses, Error and Exception. Each of those has many predefined subclasses, and programmers can add their own subclasses to represent new kinds of exception. The full tree is large, so the diagram below shows Throwable with a few of its subclasses. That is enough to see the structure that matters for handling decisions.

Throwableroot of the familyErrorleft branchError subclassesmostly serious virtualmachine problemsExceptionright branchRuntimeExceptionusually points to a bugOther Exceptionsubclassesmeant to be caughtdirect subclassdirect subclasssubclassessubclasssubclasses
How are Throwable, Error, Exception, and RuntimeException nested inside one another, and which classes sit under which parent?

Read the diagram from the top down. Every line that descends from Throwable is a subclass relationship, so every class below it is also a kind of Throwable. The split at the second level is the important part. The branch on the left leads to Error, and the branch on the right leads to Exception. RuntimeException sits inside the Exception branch, under Exception, not beside it. The source uses the split to tell the two groups apart by how a program should treat them.

Expected to Catch Versus Let Crash

Exception subclasses are meant to be caught. Error subclasses mostly mark serious virtual machine problems that should generally not be caught. RuntimeException usually points to a bug that should be fixed rather than handled. These three statements look similar, but they lead to different decisions. The first asks whether a handler is a reasonable response. The second asks whether the program can do anything sensible at all. The third asks whether the real fix is in the code.

GroupWhat the source saysCan the program ignore it?Typical response
Error and its subclassesMostly serious virtual machine problems that should generally not be caughtYes, the program may simply let it crashLet the program stop rather than continue on a bad state
RuntimeException and its subclassesUsually points to a bug that should be fixedYes, the program may simply let it crashFix the code that caused it
Other Exception subclassesMeant to be caughtNo, handling is mandatory in the sense the source discusses laterCatch the exception and respond to it

Three groups of exception classes and how a program should treat each

Why a Catch-All Handler Backfires

The source is direct about the catch-all belief. A programmer should avoid the temptation to put in a catch-all handler so that errors do not crash the program. If there is no reasonable way to respond to an error, it is usually better to let the program crash, because trying to continue in that situation tends to make things worse. In the worst case, the program keeps running and produces an incorrect answer without giving any sign that the answer might be wrong.

  • Common mistake

    Wrapping all code in a catch-all handler so the program never crashes

    What it looks like

    A handler that catches every exception and prints nothing, so the failure disappears silently.

    Why it fails

    The program keeps running on bad data and can report an incorrect result with no sign that anything went wrong.

    Do this instead

    Catch only the exceptions the code can actually respond to, and let unrecoverable problems stop the run.

  • Common mistake

    Catching a RuntimeException as a routine way to get past a bug

    What it looks like

    Catching NullPointerException or NumberFormatException everywhere and continuing as if nothing happened.

    Why it fails

    A RuntimeException usually points to a bug that should be fixed, so hiding it leaves the bug in place.

    Do this instead

    Find the cause in the code and correct it. Catch the exception only when a sensible response exists.

  • Common mistake

    Assuming an exempt group is safe to ignore

    What it looks like

    Ignoring the possibility of a serious virtual machine problem because the compiler does not require handling it.

    Why it fails

    The source says these can be ignored in the sense that the language does not force handling. It does not say they are harmless.

    Do this instead

    Keep the good practice of responding carefully, even though the compiler does not demand it.

  • Common mistake

    Reading the message only in the handler without checking the call stack when debugging

Practice Deciding What to Catch

MEDIUM

A program reads a number from a file. The file might be missing, or the text in it might not be a number. Decide which exception group each problem belongs to, using the three groups from this article. Then say whether your program should catch it, or let it crash and fix the cause. Justify each choice in one sentence.

Hints
  • Ask whether the program has a reasonable way to respond to the problem.
  • Ask whether the problem points to a bug in the code rather than a condition the program can handle.
  • Remember that an Exception subclass is meant to be caught, while a RuntimeException usually points to a bug.

Key Takeaways

  • A thrown exception is an object that carries the call stack and an error message from the failure point to the handler.
  • Throwable is the root of the exception hierarchy, with exactly two direct subclasses: Error and Exception.
  • Exception subclasses are meant to be caught, Error subclasses should generally not be caught, and RuntimeException usually points to a bug to fix.
  • Errors and RuntimeExceptions can be ignored in the sense that the program may let it crash, while other Exception subclasses make handling mandatory.
  • A catch-all handler can hide failures and produce incorrect results, so catch only what the program can reasonably respond to.