Java Exceptions
An overview of exceptions in Java — what they are, the exception hierarchy, and why exception handling matters.
An exception is what happens when your program runs into a situation it can't handle on its current path — a file that isn't there, a number divided by zero, an array index that's out of bounds. Instead of returning a wrong answer or silently corrupting state, Java stops the current method, builds an exception object describing what went wrong, and starts looking for code that knows how to deal with it. Learning the exception machinery is learning how Java tells you what went wrong, where, and what you might do about it.
What an exception actually is
An exception is a regular Java object. Specifically, an instance of a class that inherits from java.lang.Throwable. When something goes wrong, the JVM (or your own code) creates one of these objects and throws it. From that moment on, the program follows a different control flow until either a catch block accepts the exception or the thread terminates.
The object carries information: a type (the class — NullPointerException, IOException, etc.), a message (a human-readable description), and a stack trace (the call chain frozen at the moment the exception was created). When you read an exception in a console, you're reading those three things.
Exception in thread "main" java.lang.ArithmeticException: / by zero
at calc.Money.divide(Money.java:42)
at calc.App.main(App.java:11)The first line is type + message. The indented lines are the stack trace, newest call first.
Why exceptions instead of error codes
Older languages — C is the classic example — signal failure with return codes: every function returns an int, you check it, and if it's negative something went wrong. That approach has two problems:
- You can ignore the return value. A caller that forgets to check it sees no immediate failure, and the bug surfaces later in a confusing place.
- The error path clutters the happy path. Every line of real work is wrapped in
if (err) return err;.
Exceptions invert this. The default is that an unhandled exception stops execution, loudly. You opt in to handling it where you actually have a strategy. The good path stays clean; the recovery path is in its own block.
The three things that can go wrong
Java sorts everything Throwable into three buckets, and the difference matters because the language treats them differently:
Error— the JVM itself is in trouble.OutOfMemoryError,StackOverflowError. You don't catch these in normal code. There's usually nothing useful you can do.RuntimeException(a subclass ofException) — programming bugs that show up at runtime.NullPointerException,IndexOutOfBoundsException,ClassCastException. The compiler doesn't force you to handle them, because in correct code they shouldn't happen.- Checked
Exception(everything else underException) — recoverable failures the program should anticipate.IOException,SQLException. The compiler requires you to either catch them or declare them in your method'sthrowsclause.
The line between "programming bug" (runtime exception) and "anticipated failure" (checked exception) is one of Java's most argued-about design decisions. We'll come back to it in Java checked vs. unchecked exceptions.
How throwing and catching work
When a throw runs, the JVM:
- Unwinds the stack — the current method exits abruptly, then its caller does the same, and so on.
- At each frame, it checks for a
try { ... } catch (SomeType e) { ... }block whosecatchmatches the exception's type (or a supertype). - The first matching
catchwins. Control jumps there, the stack stops unwinding, and execution resumes in the catch block. - If nothing matches, the thread dies. In a single-threaded program, that means the JVM prints the stack trace and exits.
This is why a thrown exception can travel through many methods before it's caught — every uncaught throw bubbles up another frame.
A first taste
You don't have to write throw to encounter an exception — Java itself throws them when something goes wrong. Here's the simplest example: dividing an integer by zero. The JVM creates an ArithmeticException for you.
Without the try/catch, the third iteration would crash the whole program and the fourth would never execute. With it, the failure is contained: we get one error message and the loop continues. That ability — to bound the damage of a failure — is the whole point of the exception machinery.
What this part of the book covers
The remaining chapters in this part are the working vocabulary of Java exception handling, one piece at a time:
- The shape of
try/catch/finallyand what each clause is for. - Multiple catches and the multi-catch shortcut.
try-with-resourcesfor anything that needs closing.- Throwing exceptions yourself with
throw, and declaring them withthrows. - Checked vs. unchecked: which one to use and when.
- The full class hierarchy.
- Writing your own exception types for your domain.
- The principles that distinguish good exception handling from defensive noise.
Read it in order — each chapter assumes the previous one.
What's next
Exception handling starts with the most fundamental construct: the try/catch block. Continue to Java try...catch.