Exception Handling
An exception is an event that disrupts the normal flow of a program — dividing by zero, accessing an
array index that doesn't exist, or calling a method on a null reference, for example. Instead of letting
the program crash, Java lets you catch these events and decide what to do next.
try, catch, and finally
Code that might throw an exception goes inside a try block. If an exception occurs, control jumps to a matching catch block. A finally block, if present, always runs afterward — whether an exception occurred or not — which makes it ideal for cleanup work like closing a file or a database connection.
try {
int result = 10 / 0; // throws ArithmeticException
} catch (ArithmeticException e) {
System.out.println("Can't divide by zero: " + e.getMessage());
} finally {
System.out.println("This always runs");
}
Here, dividing by zero throws an ArithmeticException. The catch block handles it gracefully by printing a message instead of crashing, and the finally block runs regardless of what happened above it.
catch blocks after one try to handle different exception types differently. Java checks them in order and runs the first one that matches.Throwing an Exception Manually
You can raise an exception yourself with the throw keyword, followed by a new exception object:
throw new IllegalArgumentException("Value cannot be negative");
This is useful for enforcing your own rules — for example, rejecting an invalid input before it causes problems further down the line.
Checked vs Unchecked Exceptions
Java exceptions fall into two broad categories:
- Checked exceptions — must either be caught with a
try/catchor declared on the method withthrows. The compiler enforces this. Example:IOException, which can occur when reading a file. - Unchecked exceptions (runtime exceptions) — don't require a
throwsdeclaration or a mandatory catch. They usually signal a programming mistake. Examples:NullPointerException,ArithmeticException.
Creating a Custom Exception
You can define your own exception type by extending Exception (checked) or RuntimeException (unchecked). This lets your error messages be as specific as your own business rules:
class InvalidAgeException extends Exception {
InvalidAgeException(String message) {
super(message); // hands the message up to Exception
}
}
Worked Example: Validating Age
Here's a method that throws our custom exception when it receives an invalid age, called from inside a try/catch:
public class AgeValidator {
static void checkAge(int age) throws InvalidAgeException {
if (age < 0) {
throw new InvalidAgeException("Age cannot be negative: " + age);
}
System.out.println("Age is valid");
}
public static void main(String[] args) {
try {
checkAge(-5);
} catch (InvalidAgeException e) {
System.out.println("Caught: " + e.getMessage());
}
}
}
Because InvalidAgeException extends Exception, it's a checked exception, so checkAge must declare throws InvalidAgeException. Calling it with -5 triggers the throw, and the catch block in main prints: Caught: Age cannot be negative: -5.
Quick recap:
try/catch— attempt risky code, handle failures gracefully.finally— always runs, ideal for cleanup.throw— raise an exception manually.- Checked exceptions must be declared or caught; unchecked ones don't require this.
- Custom exceptions extend
Exception(checked) orRuntimeException(unchecked).