Module 4: Exceptions

Module Overview

Learn about exception handling and error management in Java to create more robust applications.

Learning Objectives

  • Understand the purpose of exceptions in Java
  • Identify the types of exceptions in Java: checked and unchecked
  • Use try-catch blocks to handle exceptions
  • Implement try-catch-finally blocks for resource cleanup
  • Throw exceptions using the throw statement
  • Create custom exception classes for domain-specific errors
  • Implement effective exception handling strategies

Exception Basics

What are Exceptions?

Exceptions are events that occur during program execution that disrupt the normal flow of instructions. They represent errors or exceptional conditions that need special handling.

Exception Hierarchy

Java exceptions are organized in a hierarchy with Throwable as the parent class, which has two main subclasses: Error and Exception.

// Exception hierarchy
Throwable
├── Error (unchecked) - serious problems, should not be caught
│   ├── OutOfMemoryError
│   ├── StackOverflowError
│   └── ...
└── Exception
    ├── IOException (checked)
    ├── SQLException (checked)
    └── RuntimeException (unchecked)
        ├── NullPointerException
        ├── ArrayIndexOutOfBoundsException
        ├── ArithmeticException
        └── ...

Checked vs. Unchecked Exceptions

Java has two categories of exceptions:

  • Checked Exceptions: Must be either caught or declared in the method's throws clause. Example: IOException
  • Unchecked Exceptions: Do not need to be explicitly caught or declared. They include RuntimeException and its subclasses, as well as Error and its subclasses. Example: NullPointerException

Handling Exceptions

Try-Catch Blocks

The try-catch block is used to handle exceptions in Java.

// Basic try-catch
try {
    // Code that might throw an exception
    int result = 10 / 0; // ArithmeticException
} catch (ArithmeticException e) {
    // Code to handle the exception
    System.out.println("Cannot divide by zero: " + e.getMessage());
}

Multiple Catch Blocks

You can use multiple catch blocks to handle different exceptions differently.

try {
    // Code that might throw different exceptions
    int[] array = new int[5];
    array[10] = 30; // ArrayIndexOutOfBoundsException
} catch (ArithmeticException e) {
    System.out.println("Arithmetic error: " + e.getMessage());
} catch (ArrayIndexOutOfBoundsException e) {
    System.out.println("Array index error: " + e.getMessage());
} catch (Exception e) {
    // Catches any other Exception that wasn't caught above
    System.out.println("Some other exception: " + e.getMessage());
}

Try-Catch-Finally

The finally block contains code that will be executed regardless of whether an exception occurs or not. It's commonly used for cleanup operations.

FileReader reader = null;
try {
    reader = new FileReader("file.txt");
    // Process file
} catch (FileNotFoundException e) {
    System.out.println("File not found: " + e.getMessage());
} finally {
    // This will always execute, even if an exception occurs
    if (reader != null) {
        try {
            reader.close();
        } catch (IOException e) {
            System.out.println("Error closing file: " + e.getMessage());
        }
    }
}

Try-with-Resources

Introduced in Java 7, try-with-resources automatically closes resources that implement AutoCloseable.

// Try-with-resources automatically closes the resource
try (FileReader reader = new FileReader("file.txt")) {
    // Process file
    // reader is automatically closed when the block completes
} catch (IOException e) {
    System.out.println("IO error: " + e.getMessage());
}

Throwing Exceptions

Using the throw Keyword

You can explicitly throw an exception using the throw keyword.

public void setAge(int age) {
    if (age < 0) {
        throw new IllegalArgumentException("Age cannot be negative");
    }
    this.age = age;
}

Declaring Exceptions with throws

Methods that might throw checked exceptions must declare them using the throws keyword.

public void readFile(String filename) throws IOException {
    FileReader reader = new FileReader(filename);
    // Process file
    reader.close();
}

Creating Custom Exceptions

You can create your own exception classes by extending Exception (for checked exceptions) or RuntimeException (for unchecked exceptions).

// Custom checked exception
public class InsufficientFundsException extends Exception {
    private double amount;
    
    public InsufficientFundsException(double amount) {
        super("Insufficient funds: Attempted to withdraw " + amount);
        this.amount = amount;
    }
    
    public double getAmount() {
        return amount;
    }
}

// Using the custom exception
public void withdraw(double amount) throws InsufficientFundsException {
    if (amount > balance) {
        throw new InsufficientFundsException(amount);
    }
    balance -= amount;
}

Exception Handling Best Practices

Specific Exceptions First

When using multiple catch blocks, catch more specific exceptions before more general ones.

Don't Catch and Ignore

Always handle exceptions meaningfully. Don't catch an exception and do nothing with it (empty catch block).

Clean Up Resources

Use try-with-resources or finally blocks to ensure resources are properly closed.

Document Exceptions

Use JavaDoc to document the exceptions a method may throw.

/**
 * Withdraws money from the account.
 *
 * @param amount the amount to withdraw
 * @throws InsufficientFundsException if amount is greater than current balance
 */
public void withdraw(double amount) throws InsufficientFundsException {
    // Implementation
}

Exception Translation

Convert low-level exceptions to higher-level ones that make more sense in your application's context.

public void processOrder(Order order) throws OrderProcessingException {
    try {
        databaseService.saveOrder(order);
    } catch (SQLException e) {
        // Translate the low-level SQL exception to a domain-specific one
        throw new OrderProcessingException("Failed to process order", e);
    }
}

Additional Resources

Practice Exercises

Complete these exercises to reinforce your understanding of exceptions.

Exercise 1: Bank Account Exceptions

Create a BankAccount class with the following features:

  • Methods for deposit and withdraw
  • A custom InsufficientFundsException
  • Proper exception handling for invalid inputs
  • A transfer method that handles multiple potential exceptions

Exercise 2: File Processing with Exceptions

Create a program that reads and processes a text file:

  • Use try-with-resources for file handling
  • Handle different types of I/O exceptions
  • Implement a custom FileProcessingException
  • Add exception logging and recovery strategies

Guided Projects