TutorialsJavaException Handling
Share:

Exception Handling

advanced

Part of Advanced Java

Theory

Exceptions are events that disrupt the normal flow of a program. Instead of letting your program crash, Java provides a robust mechanism to handle these errors gracefully.

What are Exceptions?

An exception is an object that represents an error or unexpected condition. When an error occurs, the method throws an exception object. The runtime system searches the call stack for a method that can handle the exception.

Method A calls Method B calls Method C
                                      ↓
                                Exception thrown
                                      ↓
                              Stack unwinding...
                        Handler found in Method A ✓

Checked vs Unchecked Exceptions

Java divides exceptions into two categories:

Checked exceptions are checked at compile-time. The compiler forces you to handle them with try-catch or declare them with throws.

  • IOException
  • SQLException
  • FileNotFoundException
try {
    FileReader file = new FileReader("test.txt");  // May throw FileNotFoundException
} catch (FileNotFoundException e) {
    System.out.println("File not found!");
}

Unchecked exceptions (RuntimeException) are not checked at compile-time. They are usually caused by programming bugs.

  • NullPointerException — calling a method on null
  • ArrayIndexOutOfBoundsException — accessing an invalid index
  • ArithmeticException — dividing by zero
  • IllegalArgumentException — invalid argument
int[] arr = new int[5];
arr[10] = 42;  // Throws ArrayIndexOutOfBoundsException at runtime

Try-Catch-Finally

The basic structure for handling exceptions:

try {
    // Code that might throw an exception
    int result = 10 / 0;
} catch (ArithmeticException e) {
    // Handle the exception
    System.out.println("Cannot divide by zero: " + e.getMessage());
} finally {
    // Always executes (whether exception occurred or not)
    System.out.println("Cleanup code here");
}
  • try: Contains the code that might throw an exception
  • catch: Handles the exception (you can have multiple catch blocks)
  • finally: Optional block that always executes, typically used for cleanup

Multiple Catch Blocks

You can catch different exception types in separate blocks. Order matters — catch more specific exceptions first:

try {
    String str = null;
    System.out.println(str.length());
 
    int[] arr = new int[3];
    arr[5] = 10;
} catch (NullPointerException e) {
    System.out.println("Null reference: " + e.getMessage());
} catch (ArrayIndexOutOfBoundsException e) {
    System.out.println("Invalid array index: " + e.getMessage());
} catch (Exception e) {
    // Catch-all for any other exceptions
    System.out.println("Some error occurred: " + e);
}

Java 7+ allows catching multiple exceptions in one block:

try {
    // risky code
} catch (NullPointerException | ArrayIndexOutOfBoundsException e) {
    System.out.println("Caught: " + e.getClass().getSimpleName());
}

throw vs throws

throw is used to explicitly throw an exception:

public void setAge(int age) {
    if (age < 0 || age > 150) {
        throw new IllegalArgumentException("Age must be between 0 and 150");
    }
    this.age = age;
}

throws is used in the method signature to declare that a method might throw an exception:

public void readFile(String path) throws IOException {
    FileReader file = new FileReader(path);
    // ...
}

throws passes the responsibility of handling the exception to the caller.

Custom Exceptions

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

public class InsufficientFundsException extends Exception {
    private double amount;
 
    public InsufficientFundsException(double amount) {
        super(String.format("Insufficient funds: $%.2f needed", amount));
        this.amount = amount;
    }
 
    public double getAmount() {
        return amount;
    }
}
 
// Usage:
public void withdraw(double amount) throws InsufficientFundsException {
    if (amount > this.balance) {
        throw new InsufficientFundsException(amount - this.balance);
    }
    this.balance -= amount;
}

Try-With-Resources

Java 7 introduced try-with-resources for automatically closing resources that implement AutoCloseable:

// Before try-with-resources (manual cleanup)
BufferedReader reader = null;
try {
    reader = new BufferedReader(new FileReader("file.txt"));
    System.out.println(reader.readLine());
} catch (IOException e) {
    e.printStackTrace();
} finally {
    if (reader != null) {
        try { reader.close(); } catch (IOException e) { }
    }
}
 
// With try-with-resources (automatic cleanup)
try (BufferedReader reader = new BufferedReader(new FileReader("file.txt"))) {
    System.out.println(reader.readLine());
} catch (IOException e) {
    e.printStackTrace();
}
// reader is automatically closed

Common Exceptions

| Exception | Cause | |-----------|-------| | NullPointerException | Calling a method or field on a null object | | ArrayIndexOutOfBoundsException | Accessing an array with an invalid index | | ArithmeticException | Dividing by zero | | NumberFormatException | Parsing an invalid number string | | IllegalArgumentException | Passing an invalid argument to a method | | IOException | Input/output operation failure | | ClassCastException | Casting an object to an incompatible type |

Use checked exceptions for recoverable conditions (file not found, network timeout). Use unchecked exceptions for programming errors (null pointer, invalid index).

Practical Examples

Example 1: Bank Account with Custom Exceptions
java
Example 2: File Processing with Try-With-Resources
java

When catching exceptions, log the full stack trace (e.printStackTrace() or a logger) during development. In production, log to a file and show user-friendly messages.

Exercises

Safe Division Calculator

easy

Write a program that asks the user for two integers and divides them. Use try-catch to handle division by zero and input mismatches (if the user enters non-numeric input).

Expected Output:

Input 10 and 0 → 'Error: Cannot divide by zero!' then 'Calculator closed.'\nInput 'abc' → 'Error: Please enter valid integers only.' then 'Calculator closed.'

Create a Custom Validation Exception

medium

Create a custom checked exception ValidationException. Write a UserRegistration class that validates username (must be 3-20 chars, no special chars), email (must contain @ and .), and password (must be 8+ chars, must contain a digit). Throw ValidationException with specific messages.

Expected Output:

Validation errors printed for invalid inputs. Success message for valid inputs.

Retry Mechanism with Exceptions

hard

Create a network request simulator that randomly fails. Implement a retry mechanism that tries an operation up to 3 times before giving up. Use a custom NetworkException. Each attempt should have a delay between retries.

Expected Output:

Attempts 1, 2, 3 may fail. If all fail, 'All retries exhausted.' is printed. If one succeeds, the data is returned. Each retry waits 1s, 2s, 3s.

Mini Quiz

Mini Quiz

Mini Project

Mini Project: Banking Application with Transaction Logging

Build a banking application that handles various transactions (deposits, withdrawals, transfers) with comprehensive exception handling. Log all errors to a file and provide user-friendly messages for each error type.

Requirements:

    Bonus Challenge

    Add a daily transaction limit. Create a DailyLimitExceededException. Also implement a batch transfer feature that attempts multiple transfers and collects all failures, not stopping at the first error.