Chapter 16: Exception Handling
In real-world applications (especially in Mumbai’s fast-paced tech world ☕), things go wrong all the time: user enters wrong input, file not found, database down, network timeout… If you don’t handle these exceptions, your program will crash and show ugly stack traces to the user.
Exception handling lets you:
- Catch errors gracefully
- Recover or inform the user
- Clean up resources properly
- Log issues for debugging
We’ll go super slowly, with lots of real-life analogies, complete runnable programs, step-by-step breakdowns, tables, common mistakes with fixes, and tons of examples you can copy-paste and run right now.
Let’s dive in!
1. What is an Exception? (The Big Idea)
An exception is an event that disrupts the normal flow of a program. Java provides a hierarchy of Exception classes (all inherit from Throwable):
|
0 1 2 3 4 5 6 7 8 9 10 |
Throwable ├── Error (serious system problems — usually don’t catch) └── Exception ├── Checked Exceptions (must be handled or declared — e.g., IOException) └── Unchecked Exceptions / RuntimeException (optional to handle — e.g., NullPointerException, ArithmeticException) |
Real-life analogy: You’re riding a bike in Mumbai traffic.
- A pothole (unexpected event) → you fall (exception)
- If you wear helmet & knee pads (try-catch) → you get hurt less
- If you ignore it → crash badly!
2. try-catch-finally (The Core Structure)
Syntax:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
try { // risky code that might throw exception } catch (ExceptionType1 e) { // handle specific exception } catch (ExceptionType2 e) { // another specific exception } catch (Exception e) { // general catch (last) // handle any other exception } finally { // always executes (cleanup) — even if exception occurs or return/break } |
Example 1: Basic try-catch
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
public class ExceptionDemo1 { public static void main(String[] args) { try { int result = 10 / 0; // ArithmeticException System.out.println(result); // never reached } catch (ArithmeticException e) { System.out.println("Cannot divide by zero! Error: " + e.getMessage()); } System.out.println("Program continues safely..."); } } |
Output:
|
0 1 2 3 4 5 6 7 |
Cannot divide by zero! Error: / by zero Program continues safely... |
Example 2: Multiple catch blocks + finally
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
import java.util.Scanner; public class ExceptionDemo2 { public static void main(String[] args) { Scanner sc = null; try { sc = new Scanner(System.in); System.out.print("Enter a number: "); int num = sc.nextInt(); // InputMismatchException possible int result = 100 / num; // ArithmeticException possible System.out.println("Result: " + result); } catch (ArithmeticException e) { System.out.println("Cannot divide by zero!"); } catch (java.util.InputMismatchException e) { System.out.println("Please enter a valid number!"); } catch (Exception e) { // Catch-all (should be last) System.out.println("Some unexpected error: " + e); } finally { System.out.println("Finally block always runs!"); if (sc != null) { sc.close(); // cleanup } } System.out.println("End of program"); } } |
Test cases:
- Enter 0 → “Cannot divide by zero!” + finally
- Enter abc → “Please enter a valid number!” + finally
- Enter 5 → “Result: 20” + finally
3. throw and throws (Manually Throwing & Declaring)
throw → manually throw an exception throws → declare that a method might throw checked exceptions
Example 3: throw + throws
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
public class ExceptionDemo3 { // Method declares it throws checked exception public static void checkAge(int age) throws IllegalArgumentException { if (age < 18) { throw new IllegalArgumentException("Age must be 18 or older!"); } System.out.println("Age is valid: " + age); } public static void main(String[] args) { try { checkAge(15); // throws exception } catch (IllegalArgumentException e) { System.out.println("Error: " + e.getMessage()); } try { checkAge(25); // OK } catch (IllegalArgumentException e) { // won't reach here } } } |
Output:
|
0 1 2 3 4 5 6 7 |
Error: Age must be 18 or older! Age is valid: 25 |
throws is mandatory for checked exceptions (e.g., IOException, SQLException). For unchecked (RuntimeException & subclasses) → optional.
4. Custom Exceptions (Your Own Exception Classes)
You can create your own exceptions by extending Exception (checked) or RuntimeException (unchecked).
Example 4: Custom Exception – InvalidBalanceException
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
// Custom checked exception public class InvalidBalanceException extends Exception { public InvalidBalanceException(String message) { super(message); } } // Custom unchecked exception (more common for business rules) public class InsufficientFundsException extends RuntimeException { public InsufficientFundsException(String message) { super(message); } } |
Using them:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
public class BankAccount { private double balance; public BankAccount(double initial) throws InvalidBalanceException { if (initial < 0) { throw new InvalidBalanceException("Initial balance cannot be negative!"); } this.balance = initial; } public void withdraw(double amount) { if (amount > balance) { throw new InsufficientFundsException("Insufficient funds! Balance: " + balance); } balance -= amount; System.out.println("Withdrew ₹" + amount + ". New balance: ₹" + balance); } } |
Test:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
try { BankAccount acc = new BankAccount(-500); // throws InvalidBalanceException } catch (InvalidBalanceException e) { System.out.println("Error: " + e.getMessage()); } BankAccount acc2 = new BankAccount(1000); try { acc2.withdraw(2000); // throws InsufficientFundsException } catch (InsufficientFundsException e) { System.out.println("Error: " + e.getMessage()); } |
5. try-with-resources (Java 7+) – Automatic Resource Management
Very useful for files, database connections, sockets — resources that need to be closed properly.
Syntax:
|
0 1 2 3 4 5 6 7 8 9 10 |
try (ResourceType res = new ResourceType()) { // use res } catch (...) { // handle } // res.close() called automatically! |
Example 5: Reading a file safely
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
import java.io.*; public class TryWithResourcesDemo { public static void main(String[] args) { try (BufferedReader br = new BufferedReader(new FileReader("data.txt"))) { String line; while ((line = br.readLine()) != null) { System.out.println(line); } } catch (IOException e) { System.out.println("File error: " + e.getMessage()); } // br.close() is automatically called here — even if exception occurs! } } |
Benefit: No need to write finally { if (br != null) br.close(); }
Quick Recap Table (Your Cheat Sheet)
| Concept | Key Points / Best Practice | Example |
|---|---|---|
| try-catch | Catch specific exceptions first, general last | catch (ArithmeticException e) |
| finally | Always runs — cleanup (close files, connections) | Close Scanner, FileReader |
| throw | Manually throw exception | throw new IllegalArgumentException(“…”) |
| throws | Declare checked exceptions in method signature | throws IOException |
| Custom Exception | Extend Exception (checked) or RuntimeException | InsufficientFundsException |
| try-with-resources | Auto-close resources (Java 7+) | try (BufferedReader br = …) |
Common Mistakes & Fixes
| Mistake | Problem | Fix |
|---|---|---|
| Catching Exception first | Specific catches never reached | Catch specific → general (Exception) last |
| Not closing resources | Resource leak (file handles, connections) | Use try-with-resources or finally |
| Throwing checked exception without throws | Compile error | Add throws or handle with try-catch |
| Empty catch block | Silent failure — bugs hidden | At least log: e.printStackTrace() |
| Catching Error | Usually don’t — serious JVM issues | Only catch Exception & subclasses |
Homework for You (Practice to Master!)
- Basic: Write a method that divides two numbers — handle ArithmeticException and InputMismatchException.
- Medium: Create custom exception NegativeNumberException. Throw it if user enters negative age.
- Advanced: Write a program that reads numbers from a file using try-with-resources. Handle FileNotFoundException and IOException.
- Fun: Create a method withdrawMoney(double amount) that throws InsufficientFundsException if balance is low.
- Challenge: Fix this buggy code:
Java0123456789101112try {int x = 10 / 0;} catch (Exception e) {System.out.println("Error");} catch (ArithmeticException e) { // unreachable!System.out.println("Divide by zero");}
You’re doing fantastic! Exception handling is what separates toy programs from production-ready, enterprise-grade code — now your programs can survive real-world chaos!
