Concepts / Multithreading and Exceptions

Multithreading and Exceptions

An exception is any circumstance during execution that is treated as a departure from the normal flow of control, and it is not limited to errors.

  • 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…

When the Normal Path Breaks

Most programs are written around a normal path. Statements run one after another, method calls go out and come back, and the result is produced. Real programs often meet situations that do not fit that path. A file may be missing, a number may be zero when it should not be, or a user may type something unexpected. Programmers need a way to deal with these situations without letting the whole program fall apart. Java offers a structured technique called exception handling for this purpose.

Before looking at the mechanism, try to hold a question in mind: if a method hits a problem halfway through its work, what should happen to the lines of code that were still waiting to run? Keep that question in mind as you read, because the answer is the heart of this topic.

Exception Versus Ordinary Error

The everyday word error suggests that something went wrong. The programming word exception is wider than that. An exception is any circumstance that comes up during execution and should be treated as a departure from the normal flow of control. Some exceptions are genuine errors, such as an operation that cannot succeed. Others are not errors at all. They are special cases that you would simply prefer not to mix into the main logic of an algorithm.

Definition

An exception is any circumstance during execution that is treated as a departure from the normal flow of control. It is not limited to errors.

The practical difference is about where control goes. An ordinary error is usually handled by the code that sees it, and the flow continues in a planned way. An exception interrupts the normal path itself. Control leaves the current statements, and the program must either find a handler for the situation or accept that the thread will crash.

Following a Thrown Exception Up the Stack

When an exception occurs during execution, we say that it has been thrown. At that moment the program leaves its normal path. The place where an exception is thrown and the place where it is caught do not have to be the same. An exception can start in one part of a program and be caught in a completely different part, including a different method. This separation is useful because the code that detects a problem does not need to know how the problem will be handled.

Read the diagram from the bottom of the chain upward. The method main calls processOrder, and processOrder calls parseNumber. The exception is thrown inside parseNumber. If parseNumber has no matching catch, control moves back to the method that called it, processOrder. If processOrder has no matching catch either, control moves back to main. The search continues up the chain until a matching handler is found or nothing catches the exception and the thread dies.

maincalls processOrderprocessOrdercalls parseNumberparseNumberexception thrown herehandler or crashmatching catch or threaddeathcallcallno catch, move upno catch, move upsearch ends
After an exception is thrown, where does control go next? It moves up through the calling methods until a matching handler is found, or the thread dies.

What the Thrown Object Carries

A detail that is easy to overlook is that the thing actually thrown is an object, not just a signal. That object travels from the point where the exception occurred to the point where it is caught and handled, and it can hold information along the way in its instance variables. The thrown object carries the call stack, typically an error message, and possibly other data.

Because the object records where the exception came from, a handler can learn about the circumstances of the problem and not just the fact that something happened. A handler that receives only a yes-or-no signal knows that a problem occurred. A handler that receives an object can inspect what the problem was and where it began.

Two Possible Outcomes After a Throw

When an exception is thrown, normal flow is interrupted. Left alone, this puts the program in danger of crashing, but a crash is not automatic. If the exception is caught and handled, the program has a chance to respond and carry on. This gives two possible outcomes after a throw: either something catches the exception and deals with it, or nothing does and the program crashes. The thread that threw the exception generally crashes when the exception is not caught.

Run try blockException thrown?Remaining statementsrunnormal pathContinue afterhandlerJump to matchinghandlerremaining statementsskippedThread crashesno handler foundnoyes, handler existsyes, nothing catches itcontinuehandled
Which statements are skipped after a throw, which handler runs, and where does execution resume? Follow the yes branch when an exception is thrown.

Notice the two branches of the flowchart. On the normal branch, the remaining statements run and execution continues. On the thrown branch, the remaining statements are skipped, control jumps to a handler if one matches, and execution resumes after that handler. If no handler matches, the thread does not get a chance to continue.

Tracing a Throw and Catch in Code

The source describes the mechanism in general terms without a code listing, so the following small Java program is an original illustration. The method divide does not handle the problem itself. It simply performs an integer division. When the divisor is zero, Java throws an exception from inside divide, and that exception has no handler in divide. Control moves up to main, where the try block has a matching catch.

java
Output
Caught: / by zero
Program continues
Notes on the code
  • divide has no handler, so the exception moves up to the caller main
  • The line after the throwing call is skipped, which matches the normal path being interrupted
  • The catch block handles the exception and execution resumes after the try statement

What do you think happens?

Before reading the output, predict whether the line that prints This line is skipped runs, and whether Program continues is printed.

Reveal answer
Answer:

The line This line is skipped does not print. The output is Caught: / by zero followed by Program continues.

The division inside divide throws an exception. Control leaves divide and the remaining statements of the try block, moves to the matching catch in main, and then execution resumes after the try statement.

Where Throwable, Error, and Exception Fit

Every exception object must belong to a subclass of the standard class java.lang.Throwable. Each distinct type of exception is usually represented by its own subclass of Throwable. Throwable has two direct subclasses, Error and Exception. These subclasses form a class hierarchy that expresses how the various kinds of exception relate to one another.

Throwablebase class of allexceptionsErrordirect subclassSpecific exceptiontypessubclasses, not listed insourceExceptiondirect subclassextendsextendsextends
Where do Throwable, Error, and Exception sit relative to each other? Each box is a class and each line shows which class extends which. Lower levels are simplified because the source does not list the individual predefined subclasses.

Read the tree as a family tree of classes. The lines show extension, so each child is a more specific kind of its parent. Throwable is the root that every exception object belongs to. Error and Exception sit one level below it. The specific exception types that a program actually throws live further down, under one of these two branches.

Mistakes Beginners Make with Exceptions

  • Common mistake

    Assuming every exception is an error

    Why it fails

    The source states the programming word exception is wider than error. Some exceptions are special cases that simply should not be mixed into the main logic of an algorithm.

    Do this instead

    Ask whether the situation is a genuine failure or a departure from the normal path. Both count as exceptions.

  • Common mistake

    Assuming a throw always crashes the program

    Why it fails

    A crash is not automatic. If the exception is caught and handled, the program can respond and carry on.

    Do this instead

    After a throw, check whether a matching handler exists somewhere up the chain of calls.

  • Common mistake

    Assuming the throw and the catch must be in the same method

    Why it fails

    The throw and catch can occur in different parts of a program, including different methods.

    Do this instead

    Trace upward through the callers to find where the exception will be caught.

  • Common mistake

    Treating the thrown exception as only a signal

    Why it fails

    The thrown item is an object. It carries the call stack, typically an error message, and possibly other data in its instance variables.

    Do this instead

    Inspect the exception object in the handler to learn about the circumstances, not just that something happened.

Exceptions and Threads

This topic's title links exceptions to multithreading, and the source's statement about threads is specific. When an exception is not caught, the thread that threw it generally crashes. The thread is the unit where the exception was thrown and where the call stack was built up.

Trace a Scenario Before You Run It

MEDIUM

A method readConfig calls parseLine, and parseLine throws an exception. The only catch in the program is in main, which calls readConfig. Describe the path the exception takes, which methods have their remaining statements skipped, and where execution resumes if the catch in main handles the exception.

Hints
  • Start at the method where the exception is thrown and follow the calls upward, the same way the call stack diagram does.
  • A method with no matching catch passes control to its caller. Skipped statements are those after the throwing point in every method the exception leaves.
  • Execution resumes after the try statement in main, once the handler finishes.

Key Takeaways

  • An exception is any circumstance during execution that is treated as a departure from the normal flow of control, and it is not limited to errors.
  • A thrown exception interrupts normal flow, and it either gets caught and handled so the program can continue, or nothing catches it and the thread that threw it generally crashes.
  • The throw and the catch can occur in different methods, so control may pass up through several callers before a matching handler is found.
  • The thrown item is an object that carries the call stack, typically an error message, and possibly other data.
  • Every exception object belongs to the Throwable hierarchy, with Error and Exception as its two direct subclasses.