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.
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
- Statements in try run until one raises an exception; the rest of try is skipped.
- Python checks the except clauses in order and runs the first one whose type matches.
- If nothing was raised, the else block runs instead.
- 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.
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.
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.
Could not read quantity: For input string: "abc"
Program continues.- The try block contains the statement that can fail.
Integer.parseIntthrows 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?
Reveal 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.
Following the failure in the QuantityReader example
Trace which statements run and which are skipped when the input is abc.
- 1Set the input
input holds the text abc, which cannot be converted to an integer.
- 2Enter the try block
The program begins the statements that might fail.
- 3Attempt the conversion
Integer.parseInt(input)fails, and an exception object is created that carries the call stack and an error message. - 4Skip the remaining try statements
The line that assigns quantity and the line that prints Quantity: never run.
- 5Run the matching catch block
The catch block for
NumberFormatExceptionreceives the object as e and prints its message. - 6Continue after the statement
The try..catch is finished, so the final line prints Program continues.
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.
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.
| Group | What the source says | Can the program ignore it? | Typical response |
|---|---|---|---|
| Error and its subclasses | Mostly serious virtual machine problems that should generally not be caught | Yes, the program may simply let it crash | Let the program stop rather than continue on a bad state |
| RuntimeException and its subclasses | Usually points to a bug that should be fixed | Yes, the program may simply let it crash | Fix the code that caused it |
| Other Exception subclasses | Meant to be caught | No, handling is mandatory in the sense the source discusses later | Catch 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 likeA handler that catches every exception and prints nothing, so the failure disappears silently.
Why it failsThe program keeps running on bad data and can report an incorrect result with no sign that anything went wrong.
Do this insteadCatch 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 likeCatching NullPointerException or NumberFormatException everywhere and continuing as if nothing happened.
Why it failsA
RuntimeExceptionusually points to a bug that should be fixed, so hiding it leaves the bug in place.Do this insteadFind 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 likeIgnoring the possibility of a serious virtual machine problem because the compiler does not require handling it.
Why it failsThe 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 insteadKeep 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
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
RuntimeExceptionusually 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
RuntimeExceptionusually 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.