15. Exception Handling
Exceptions are objects that represent **errors at runtime**. This lecture covers `try` / `catch` / `finally`, the difference between checked and unchecked exceptions, custom exceptions, and try-with-resources.
What you'll learn
- 1Catch and rethrow with `try` / `catch` / `finally`
- 2Distinguish checked vs unchecked exceptions
- 3Create custom exception classes
- 4Auto-close resources with try-with-resources
Overview
Exceptions are objects that represent **errors at runtime**. This lecture covers `try` / `catch` / `finally`, the difference between checked and unchecked exceptions, custom exceptions, and try-with-resources.
Core Concepts
1) `try` / `catch` / `finally`
try {
int x = Integer.parseInt("abc");
} catch (NumberFormatException e) {
System.out.println("parse failed: " + e.getMessage());
} finally {
System.out.println("always runs");
}2) Checked vs unchecked
- **Checked** (`IOException`, ...) β the compiler forces you to handle or declare with `throws`
- **Unchecked** (`RuntimeException` and subclasses) β programmer errors, the compiler doesn't force handling
3) Custom exception
public class InsufficientBalanceException extends RuntimeException {
public InsufficientBalanceException(String msg) { super(msg); }
}4) `throw` / `throws`
static int divide(int a, int b) {
if (b == 0) throw new IllegalArgumentException("b != 0");
return a / b;
}
static void writeFile() throws java.io.IOException { ... }5) try-with-resources
try (var br = java.nio.file.Files.newBufferedReader(java.nio.file.Path.of("a.txt"))) {
String line = br.readLine();
} // br.close() called automaticallyAny resource implementing `AutoCloseable` works.
Examples
Example 1 β `BasicTryCatch.java`
public class BasicTryCatch {
public static void main(String[] args) {
try {
int n = Integer.parseInt("abc");
System.out.println(n);
} catch (NumberFormatException e) {
System.out.println("parse failed: " + e.getMessage());
} finally {
System.out.println("done");
}
}
}**Output**
parse failed: For input string: "abc"
doneExample 2 β `MultiCatch.java`
public class MultiCatch {
public static void main(String[] args) {
try {
riskyOp(Integer.parseInt(args.length > 0 ? args[0] : "0"));
} catch (NumberFormatException | ArithmeticException e) {
System.out.println("error: " + e.getClass().getSimpleName());
}
}
static void riskyOp(int n) { System.out.println(10 / n); }
}**Note:** `|` joins multiple exception types in one `catch` arm.
Example 3 β `CustomException.java`
public class CustomException {
static class InsufficientBalanceException extends RuntimeException {
InsufficientBalanceException(String msg) { super(msg); }
}
static void withdraw(long balance, long amount) {
if (amount > balance) throw new InsufficientBalanceException("need " + amount + ", have " + balance);
}
public static void main(String[] args) {
try {
withdraw(1000, 5000);
} catch (InsufficientBalanceException e) {
System.out.println(e.getMessage());
}
}
}**Output**
need 5000, have 1000Example 4 β `TryWithResources.java`
import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
public class TryWithResources {
public static void main(String[] args) throws IOException {
try (BufferedReader br = new BufferedReader(new StringReader("line1\nline2"))) {
String s;
while ((s = br.readLine()) != null) System.out.println("> " + s);
} // br closed automatically
}
}**Output**
> line1
> line2Common Mistakes
- Catching `Exception` (or worse, `Throwable`) β too broad, hides bugs
- Empty catch blocks β silent failures
- Catching an exception only to log and rethrow without context
- Forgetting to close resources without try-with-resources
- Throwing a checked exception from `main` without `throws` clause
Summary
- Catch the **specific** exception, then act on it
- Use try-with-resources for any `AutoCloseable`
- Define custom exceptions for domain-specific errors
Practice
# Practice - 15. Exception Handling
## Exercise 1 β Safe division
- File: `Homework01.java`
- Key concepts: `try` / `catch`
Requirements
- Define `static int safeDiv(int a, int b)` that returns -1 on `ArithmeticException`.
- In main call `safeDiv(10, 2)` and `safeDiv(10, 0)`.
Expected output
5
-1## Exercise 2 β `BankAccount` with custom exception
- File: `Homework02.java`
- Key concepts: custom exception, `throw`
Requirements
- Class `Account` with `private long balance`.
- `withdraw(long)` throws `InsufficientBalanceException` if amount > balance.
- Catch and print the message in main.
Expected output
balance=10000
withdraw 5000 -> balance=5000
withdraw 6000 -> need 6000, have 5000## Solutions After trying it yourself, compare with [`answer/`](./answer/).
Solution code (homework/answer/)
answer/Homework01.java
/** Safe division. */
public class Homework01 {
public static void main(String[] args) {
System.out.println(safeDiv(10, 2));
System.out.println(safeDiv(10, 0));
}
static int safeDiv(int a, int b) {
try {
return a / b;
} catch (ArithmeticException e) {
return -1;
}
}
}
answer/Homework02.java
/** BankAccount with custom exception. */
public class Homework02 {
static class InsufficientBalanceException extends RuntimeException {
InsufficientBalanceException(String m) { super(m); }
}
static class Account {
private long balance;
Account(long b) { this.balance = b; }
long getBalance() { return balance; }
void withdraw(long amount) {
if (amount > balance)
throw new InsufficientBalanceException("need " + amount + ", have " + balance);
balance -= amount;
}
}
public static void main(String[] args) {
Account a = new Account(10_000);
System.out.println("balance=" + a.getBalance());
a.withdraw(5_000);
System.out.println("withdraw 5000 -> balance=" + a.getBalance());
try {
a.withdraw(6_000);
} catch (InsufficientBalanceException e) {
System.out.println("withdraw 6000 -> " + e.getMessage());
}
}
}
Try It Yourself
cd 04_io/15_exception/src
javac BasicTryCatch.java
java BasicTryCatchNext Lecture
[16_File_IO](../16_νμΌ_μ μΆλ ₯/) β read and write with the modern NIO.2 API.
All lecture materials and example code are openly available on GitHub.
View on GitHub β