
Exceptions are Java’s way of handling errors and unexpected conditions. This cheat sheet covers the exception hierarchy, common exceptions you’ll encounter, and patterns for handling them effectively.
Exception Hierarchy
Throwable
|
+-- Error (don't catch these)
| +-- OutOfMemoryError
| +-- StackOverflowError
| +-- VirtualMachineError
|
+-- Exception
|
+-- RuntimeException (unchecked)
| +-- NullPointerException
| +-- ArrayIndexOutOfBoundsException
| +-- IllegalArgumentException
| +-- IllegalStateException
| +-- ClassCastException
| +-- ArithmeticException
| +-- NumberFormatException
|
+-- IOException (checked)
+-- SQLException (checked)
+-- ClassNotFoundException (checked)
Checked vs Unchecked
| Type | Must Handle? | Examples | When to Use |
|---|---|---|---|
| Checked | Yes (catch or declare) | IOException, SQLException | Recoverable conditions |
| Unchecked (Runtime) | No | NullPointerException, IllegalArgumentException | Programming errors |
| Error | No (don’t catch) | OutOfMemoryError, StackOverflowError | JVM problems |
Basic Exception Handling
Try-Catch
try {
int result = 10 / 0;
} catch (ArithmeticException e) {
System.out.println("Cannot divide by zero: " + e.getMessage());
}
Try-Catch-Finally
FileReader reader = null;
try {
reader = new FileReader("file.txt");
// read file
} catch (FileNotFoundException e) {
System.out.println("File not found: " + e.getMessage());
} finally {
// Always executes, even if exception thrown
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
// Handle close error
}
}
}
Try-With-Resources (Java 7+)
// Resources auto-closed when block exits
try (FileReader reader = new FileReader("file.txt");
BufferedReader br = new BufferedReader(reader)) {
String line = br.readLine();
System.out.println(line);
} catch (IOException e) {
System.out.println("Error reading file: " + e.getMessage());
}
// No finally needed - resources closed automatically
Multiple Catch Blocks
try {
// risky code
} catch (FileNotFoundException e) {
// Handle file not found specifically
} catch (IOException e) {
// Handle other IO errors
} catch (Exception e) {
// Catch-all for anything else
}
// Order matters: specific exceptions first, general last
Multi-Catch (Java 7+)
try {
// risky code
} catch (IOException | SQLException e) {
// Handle either exception the same way
System.out.println("Error: " + e.getMessage());
}
Throwing Exceptions
Throw Statement
public void setAge(int age) {
if (age < 0) {
throw new IllegalArgumentException("Age cannot be negative: " + age);
}
this.age = age;
}
public void withdraw(double amount) {
if (amount > balance) {
throw new IllegalStateException("Insufficient funds");
}
balance -= amount;
}
Throws Declaration
// Declare checked exceptions in method signature
public String readFile(String path) throws IOException {
return Files.readString(Path.of(path));
}
// Multiple exceptions
public void processData(String path) throws IOException, SQLException {
// code that might throw either
}
// Callers must handle or propagate
public void caller() {
try {
String content = readFile("data.txt");
} catch (IOException e) {
// handle it
}
}
// Or propagate further
public void caller() throws IOException {
String content = readFile("data.txt");
}
Common Exceptions Reference
NullPointerException
// Cause: calling method on null reference
String s = null;
s.length(); // NullPointerException
// Prevention
if (s != null) {
s.length();
}
// Or use Optional
Optional.ofNullable(s).map(String::length).orElse(0);
// Java 14+ helpful messages show which variable was null
// "Cannot invoke String.length() because s is null"
ArrayIndexOutOfBoundsException
// Cause: accessing invalid array index
int[] arr = {1, 2, 3};
arr[5]; // ArrayIndexOutOfBoundsException
// Prevention
if (index >= 0 && index < arr.length) {
arr[index];
}
IndexOutOfBoundsException
// Cause: invalid index in List or String
List<String> list = List.of("a", "b");
list.get(10); // IndexOutOfBoundsException
String s = "hello";
s.charAt(10); // StringIndexOutOfBoundsException
// Prevention
if (index >= 0 && index < list.size()) {
list.get(index);
}
ClassCastException
// Cause: invalid type cast
Object obj = "hello";
Integer num = (Integer) obj; // ClassCastException
// Prevention: check type first
if (obj instanceof Integer) {
Integer num = (Integer) obj;
}
// Java 16+ pattern matching
if (obj instanceof Integer num) {
// num is already cast
}
NumberFormatException
// Cause: parsing invalid number string
Integer.parseInt("abc"); // NumberFormatException
Double.parseDouble("12.34.56"); // NumberFormatException
// Prevention
public static Integer parseIntSafe(String s) {
try {
return Integer.parseInt(s);
} catch (NumberFormatException e) {
return null; // or default value
}
}
IllegalArgumentException
// Cause: invalid method argument
// Throw this in your own code for validation
public void setPercentage(int percent) {
if (percent < 0 || percent > 100) {
throw new IllegalArgumentException(
"Percentage must be 0-100, got: " + percent);
}
this.percent = percent;
}
IllegalStateException
// Cause: method called at wrong time/state
// Use when object is in wrong state for operation
public void start() {
if (running) {
throw new IllegalStateException("Already running");
}
running = true;
}
public void next() {
if (!hasNext()) {
throw new IllegalStateException("No more elements");
}
// return next element
}
UnsupportedOperationException
// Cause: operation not supported
List<String> immutable = List.of("a", "b", "c");
immutable.add("d"); // UnsupportedOperationException
// Throw in your code for unimplemented methods
public void optionalFeature() {
throw new UnsupportedOperationException("Not implemented");
}
ConcurrentModificationException
// Cause: modifying collection while iterating
List<String> list = new ArrayList<>(List.of("a", "b", "c"));
for (String s : list) {
list.remove(s); // ConcurrentModificationException
}
// Solution 1: Use Iterator.remove()
Iterator<String> it = list.iterator();
while (it.hasNext()) {
String s = it.next();
if (condition) {
it.remove(); // Safe
}
}
// Solution 2: Use removeIf()
list.removeIf(s -> s.equals("b"));
// Solution 3: Collect items to remove, then remove
List<String> toRemove = new ArrayList<>();
for (String s : list) {
if (condition) toRemove.add(s);
}
list.removeAll(toRemove);
IOException
// Cause: I/O operation failure
// Subclasses: FileNotFoundException, EOFException, etc.
try {
String content = Files.readString(Path.of("missing.txt"));
} catch (NoSuchFileException e) {
System.out.println("File doesn't exist: " + e.getFile());
} catch (IOException e) {
System.out.println("IO error: " + e.getMessage());
}
FileNotFoundException
// Cause: file doesn't exist or can't be opened
try {
FileReader reader = new FileReader("missing.txt");
} catch (FileNotFoundException e) {
System.out.println("File not found: " + e.getMessage());
}
// Prevention: check first
File file = new File("data.txt");
if (file.exists() && file.canRead()) {
// safe to open
}
Creating Custom Exceptions
Unchecked Exception
public class InvalidOrderException extends RuntimeException {
private final String orderId;
public InvalidOrderException(String message, String orderId) {
super(message);
this.orderId = orderId;
}
public InvalidOrderException(String message, String orderId, Throwable cause) {
super(message, cause);
this.orderId = orderId;
}
public String getOrderId() {
return orderId;
}
}
// Usage
throw new InvalidOrderException("Order total cannot be negative", "ORD-123");
Checked Exception
public class InsufficientFundsException extends Exception {
private final double requested;
private final double available;
public InsufficientFundsException(double requested, double available) {
super(String.format("Requested %.2f but only %.2f available",
requested, available));
this.requested = requested;
this.available = available;
}
public double getRequested() { return requested; }
public double getAvailable() { return available; }
}
// Usage - must be declared or caught
public void withdraw(double amount) throws InsufficientFundsException {
if (amount > balance) {
throw new InsufficientFundsException(amount, balance);
}
balance -= amount;
}
Exception Handling Patterns
Wrap and Rethrow
public void processFile(String path) throws ProcessingException {
try {
String content = Files.readString(Path.of(path));
// process content
} catch (IOException e) {
// Wrap low-level exception in domain exception
throw new ProcessingException("Failed to process " + path, e);
}
}
Log and Rethrow
public void process() throws ServiceException {
try {
// risky operation
} catch (Exception e) {
logger.error("Processing failed", e);
throw e; // or wrap in ServiceException
}
}
Convert to Unchecked
// In lambdas where checked exceptions are inconvenient
list.stream()
.map(path -> {
try {
return Files.readString(Path.of(path));
} catch (IOException e) {
throw new UncheckedIOException(e);
}
})
.collect(Collectors.toList());
Provide Default Value
public String readFileOrDefault(String path, String defaultValue) {
try {
return Files.readString(Path.of(path));
} catch (IOException e) {
return defaultValue;
}
}
// With Optional
public Optional<String> readFile(String path) {
try {
return Optional.of(Files.readString(Path.of(path)));
} catch (IOException e) {
return Optional.empty();
}
}
Retry Pattern
public String fetchWithRetry(String url, int maxAttempts) throws IOException {
IOException lastException = null;
for (int attempt = 1; attempt <= maxAttempts; attempt++) {
try {
return fetch(url);
} catch (IOException e) {
lastException = e;
System.out.println("Attempt " + attempt + " failed, retrying...");
try {
Thread.sleep(1000 * attempt); // Exponential backoff
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
throw new IOException("Interrupted during retry", ie);
}
}
}
throw new IOException("Failed after " + maxAttempts + " attempts", lastException);
}
Exception Information Methods
try {
// risky code
} catch (Exception e) {
// Get message
String msg = e.getMessage();
// Get localized message
String localMsg = e.getLocalizedMessage();
// Get cause (wrapped exception)
Throwable cause = e.getCause();
// Get stack trace
StackTraceElement[] stack = e.getStackTrace();
// Print stack trace to stderr
e.printStackTrace();
// Print to specific stream
e.printStackTrace(System.out);
// Get stack trace as string
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
String stackTrace = sw.toString();
}
Best Practices
Do
// Catch specific exceptions
try {
// code
} catch (FileNotFoundException e) {
// handle specifically
}
// Include context in messages
throw new IllegalArgumentException("User ID must be positive, got: " + userId);
// Clean up resources with try-with-resources
try (Connection conn = getConnection()) {
// use connection
}
// Preserve the cause chain
throw new ServiceException("Failed to process order", originalException);
// Use standard exceptions when appropriate
throw new IllegalArgumentException("Invalid input");
throw new IllegalStateException("Not initialized");
throw new UnsupportedOperationException("Not implemented");
Don’t
// Don't catch Exception or Throwable broadly
try {
// code
} catch (Exception e) { // Too broad
// might hide programming errors
}
// Don't swallow exceptions silently
try {
// code
} catch (Exception e) {
// Nothing here - bad!
}
// Don't use exceptions for control flow
try {
while (true) {
array[i++]; // Don't rely on ArrayIndexOutOfBoundsException
}
} catch (ArrayIndexOutOfBoundsException e) {
// finished iteration - bad pattern
}
// Don't throw Exception or Throwable directly
throw new Exception("Error"); // Too generic
Quick Reference Table
| Exception | Type | Common Cause |
|---|---|---|
| NullPointerException | Unchecked | Method call on null |
| ArrayIndexOutOfBoundsException | Unchecked | Invalid array index |
| ClassCastException | Unchecked | Invalid type cast |
| NumberFormatException | Unchecked | Invalid number parsing |
| IllegalArgumentException | Unchecked | Invalid method argument |
| IllegalStateException | Unchecked | Wrong object state |
| UnsupportedOperationException | Unchecked | Operation not supported |
| ConcurrentModificationException | Unchecked | Collection modified during iteration |
| IOException | Checked | I/O operation failure |
| FileNotFoundException | Checked | File doesn’t exist |
| SQLException | Checked | Database error |
| ClassNotFoundException | Checked | Class not found at runtime |
| InterruptedException | Checked | Thread interrupted |
Related: Java Exception Handling | Reading and Writing Files in Java | Java Collections Cheat Sheet
Sources
- Oracle. “Lesson: Exceptions.” docs.oracle.com/javase/tutorial/essential/exceptions
- Oracle. “java.lang Package.” docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/package-summary.html


