Exception handling
try/catch/finally, the exception hierarchy, checked vs unchecked, throw, throws and multi-catch.
Things go wrong: files go missing, users type letters where numbers belong, networks drop, and bugs lurk. Java handles errors with exceptions: objects that describe a problem and interrupt normal flow until some code handles them. Good exception handling is the difference between a program that crashes with a stack trace and one that explains the problem and recovers.
What happens without handling#
The exception was thrown, nothing caught it, so the JVM printed the stack trace and ended the program.
Reading a stack trace
- The first line gives the exception type and message: here
ArrayIndexOutOfBoundsException: Index 5 out of bounds for length 3. - Each
atline is a method call, most recent first, with the file and line number. - Find the first line that points to your code. That is where to start debugging.
- A
Caused by:section shows the underlying exception when one exception wraps another.
try / catch#
Put risky code in a try block and handle failures in catch:
When parseInt throws, the rest of the try block is skipped and control jumps to the matching catch. After the catch, execution continues normally.
Useful methods on every exception: getMessage(), getClass().getSimpleName(), getCause() and printStackTrace().
The exception hierarchy#
A catch for a type also catches all its subclasses: catch (IllegalArgumentException e) catches NumberFormatException too.
Checked vs unchecked exceptions#
This distinction is unique to Java and very important:
If you call a method that throws a checked exception and neither catch nor declare it, the code does not compile:
throws: declaring exceptions#
A method that does not want to handle a checked exception itself declares it with throws, passing responsibility to its caller:
NoSuchFileException is a subclass of IOException, so the catch handles it.
throw: raising your own exceptions#
Use throw to signal that something is wrong. This is called failing fast: detect the problem as early as possible, with a clear message:
Don't confuse the keywords: throw (a statement) raises an exception now; throws (in a method signature) declares that the method might.
Good standard exceptions to reuse:
Multiple catch blocks and multi-catch#
Order catch blocks from most specific to most general:
- Only the first matching catch runs.
- Multi-catch (
A | B) shares one handler; the types must not be subclasses of each other.
finally: always clean up#
Code in finally runs whether the try succeeds, throws, or even returns:
finally is for releasing resources: closing files, database connections, locks. For anything AutoCloseable, try-with-resources (next lesson) does this more safely. Never return from inside finally: it silently discards any exception in flight.
How exceptions propagate#
An uncaught exception travels up the call stack until some method catches it:
Catch an exception at the level that can actually do something useful about it: retry, use a default, show a message, or translate it. If a method can't handle it meaningfully, let it propagate.
Best practices#
- Never swallow exceptions silently.
catch (Exception e) { }hides bugs. At minimum, log it. - Catch specific types, not
ExceptionorThrowable, except at the very top of an application (e.g. to log and show a friendly error). - Don't use exceptions for normal control flow. Check
hasNextInt()ormap.containsKey()when absence is expected. - Don't catch
Errors likeOutOfMemoryError; the JVM is in trouble and you can rarely recover. - Write helpful messages that include the offending value:
"Invalid quantity: -3"beats"error". - Validate early with
Objects.requireNonNulland argument checks at the start of public methods. - Preserve the cause when wrapping exceptions (next lesson).
Common mistakes#
- Catching a general type before a specific one (compile error: the exception has already been caught).
- Printing
eand continuing as if nothing happened, leaving the program in a broken state. - Declaring
throws Exceptioneverywhere, which forces every caller to handle "anything". - Assuming
finallywon't run when thetryblock returns.
What's next#
Standard exceptions only go so far. Next you will design custom exceptions for your own domain, chain causes, and use try-with-resources to close files and connections automatically.
Check your understanding
Quick quiz
1.Which of these is a checked exception?
2.When does a
finallyblock run?3.Why does
catch (Exception e) { } catch (IOException e) { }fail to compile?
Finished reading?
Mark this lesson complete to track your progress.