BackendBench
Coffee

Unravel › Java concepts › Errors and logging

Errors and logging

Exceptions: try, catch, throw

An exception is how Java reports that something went wrong.

🔎 Unravel this example

At a glance

Mental model

A fire alarm: when something goes wrong in a room, the alarm travels outward through the building until someone responsible takes charge.

What happens, in order
  1. 1try { ... } catch (IOException e) { ... } finally { ... }: the catch runs if a matching exception occurs in the try; the finally block runs whether or not there was one
  2. 2Checked exceptions (IOException, SQLException) must be declared with throws or handledUnchecked ones (RuntimeException and subclasses such as NullPointerException, IllegalArgumentException) need no declaration.
  3. 3Several types can share a handler: catch (IOException | SQLException e)Catch the most specific type first.
  4. 4throw new IllegalStateException("message", cause) raises onePass the original exception as the cause so its stack trace is not lost.
Remember
Watch out
Empty catch blocksLosing the cause when wrappingCatching Exception too broadlyLogging and rethrowing at every layerIgnoring InterruptedException
Example (highlighted lines explain it)
try {    int n = Integer.parseInt(input);    process(n);} catch (NumberFormatException e) {    throw new IllegalArgumentException("not a number: " + input, e);} finally {    log.debug("done with {}", input);}
Read the full explanation (about 2 min)

An exception is how Java reports that something went wrong. throw raises it, the call stack unwinds until a matching catch handles it, and finally runs either way.

A mental model

A fire alarm: when something goes wrong in a room, the alarm travels outward through the building until someone responsible takes charge. If nobody does, the whole program stops.

How it works

try { ... } catch (IOException e) { ... } finally { ... }: the catch runs if a matching exception occurs in the try; the finally block runs whether or not there was one.

Checked exceptions (IOException, SQLException) must be declared with throws or handled. Unchecked ones (RuntimeException and subclasses such as NullPointerException, IllegalArgumentException) need no declaration.

Several types can share a handler: catch (IOException | SQLException e). Catch the most specific type first.

throw new IllegalStateException("message", cause) raises one. Pass the original exception as the cause so its stack trace is not lost.

Going deeper

An empty catch (or only e.printStackTrace()) swallows the problem: the program carries on in a broken state. At least log it with the exception object, or rethrow.

Catching Exception or Throwable broadly also catches things you cannot handle (InterruptedException must restore the interrupt flag, OutOfMemoryError should not be swallowed).

Do not use exceptions for normal control flow, and do not log and rethrow the same exception at every layer: you get the same trace five times. Handle it once, where you can act.

A return inside finally overrides a thrown exception and hides it.

Under the hood

The JVM keeps an exception table per method: ranges of bytecode with handler addresses. Throwing creates the exception object and fills in the stack trace, which is the expensive part (hence the advice not to use exceptions for flow control).

Common mistakes

  • Empty catch blocks.
  • Losing the cause when wrapping.
  • Catching Exception too broadly.
  • Logging and rethrowing at every layer.
  • Ignoring InterruptedException.

How Unravel recognises it

When you paste code, Unravel looks for these signs of exceptions: try, catch, throw. Spotting them yourself is a good habit when you read unfamiliar code:

Part of a learning path

Related concepts

Builds on this

Frequently asked questions

What is Exceptions: try, catch, throw?

An exception is how Java reports that something went wrong. throw raises it, the call stack unwinds until a matching catch handles it, and finally runs either way.

What are the most common mistakes with Exceptions: try, catch, throw?

Empty catch blocks. Losing the cause when wrapping. Catching Exception too broadly. Logging and rethrowing at every layer. Ignoring InterruptedException.

How can I see Exceptions: try, catch, throw in real code?

Paste your own Java into Unravel and it will point out where exceptions: try, catch, throw appears, explain how it works at the detail level you choose, and draw the flow of the code around it.