Catching Exceptions

Introduction

Catching exceptions means handling errors gracefully using catch block.


Basic Syntax

try {
    // Code that may throw exception
} catch (ExceptionType e) {
    // Handle exception
}

Simple Example

public class Main {
    public static void main(String[] args) {
        try {
            int result = 10 / 0;
            System.out.println(result);
        } catch (ArithmeticException e) {
            System.out.println("Cannot divide by zero");
        }
        System.out.println("Program continues");
    }
}

Output:

Cannot divide by zero
Program continues

Multiple catch Blocks

public class Main {
    public static void main(String[] args) {
        try {
            String str = null;
            System.out.println(str.length());  // NullPointerException
            int result = 10 / 0;               // ArithmeticException
        } catch (NullPointerException e) {
            System.out.println("Null pointer error");
        } catch (ArithmeticException e) {
            System.out.println("Arithmetic error");
        } catch (Exception e) {
            System.out.println("General error");
        }
    }
}

Rule: Specific exceptions before general Exception.


Multi-catch (Java 7+)

Catch multiple exceptions in one block.

public class Main {
    public static void main(String[] args) {
        try {
            int[] arr = {1, 2, 3};
            System.out.println(arr[10]);
        } catch (ArithmeticException | ArrayIndexOutOfBoundsException e) {
            System.out.println("Error: " + e.getMessage());
        }
    }
}

Exception Object Methods

public class Main {
    public static void main(String[] args) {
        try {
            int result = 10 / 0;
        } catch (ArithmeticException e) {
            // Get error message
            System.out.println("Message: " + e.getMessage());

            // Get exception info
            System.out.println("ToString: " + e.toString());

            // Print stack trace
            e.printStackTrace();
        }
    }
}

Catching Order

// ✓ Correct - specific first
try {
    // code
} catch (FileNotFoundException e) {
    // Handle file not found
} catch (IOException e) {
    // Handle other IO errors
} catch (Exception e) {
    // Handle any other
}

// ✗ Wrong - general first
try {
    // code
} catch (Exception e) {  // Catches everything
    // ...
} catch (IOException e) {  // Unreachable!
    // ...
}

Nested try-catch

public class Main {
    public static void main(String[] args) {
        try {
            System.out.println("Outer try");

            try {
                int result = 10 / 0;
            } catch (ArithmeticException e) {
                System.out.println("Inner catch: " + e.getMessage());
            }

            String str = null;
            str.length();

        } catch (NullPointerException e) {
            System.out.println("Outer catch: " + e.getMessage());
        }
    }
}

Complete Example: File & Array

import java.io.*;

public class Main {
    public static void main(String[] args) {
        BufferedReader reader = null;

        try {
            // File operation
            reader = new BufferedReader(new FileReader("data.txt"));
            String line = reader.readLine();

            // Array operation
            int[] numbers = {1, 2, 3};
            System.out.println(numbers[0]);

            // Arithmetic operation
            int result = 10 / 2;

            System.out.println("All operations successful");

        } catch (FileNotFoundException e) {
            System.out.println("File not found: " + e.getMessage());
        } catch (IOException e) {
            System.out.println("IO error: " + e.getMessage());
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("Array error: " + e.getMessage());
        } catch (ArithmeticException e) {
            System.out.println("Math error: " + e.getMessage());
        } finally {
            try {
                if (reader != null) {
                    reader.close();
                }
            } catch (IOException e) {
                System.out.println("Error closing file");
            }
        }
    }
}

Catching Custom Exceptions

class InvalidAgeException extends Exception {
    InvalidAgeException(String message) {
        super(message);
    }
}

class Person {
    void setAge(int age) throws InvalidAgeException {
        if (age < 0 || age > 150) {
            throw new InvalidAgeException("Invalid age: " + age);
        }
        System.out.println("Age set: " + age);
    }
}

public class Main {
    public static void main(String[] args) {
        Person p = new Person();

        try {
            p.setAge(25);
            p.setAge(200);  // Will throw
        } catch (InvalidAgeException e) {
            System.out.println("Error: " + e.getMessage());
        }
    }
}

Getting Exception Information

public class Main {
    public static void main(String[] args) {
        try {
            int[] arr = new int[5];
            arr[10] = 50;
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("Exception caught!");
            System.out.println();

            // Different ways to get info
            System.out.println("1. getMessage(): " + e.getMessage());
            System.out.println();

            System.out.println("2. toString(): " + e.toString());
            System.out.println();

            System.out.println("3. printStackTrace():");
            e.printStackTrace();
        }
    }
}

Exception Handling in Methods

class Calculator {
    int divide(int a, int b) {
        try {
            return a / b;
        } catch (ArithmeticException e) {
            System.out.println("Error: " + e.getMessage());
            return 0;
        }
    }
}

public class Main {
    public static void main(String[] args) {
        Calculator calc = new Calculator();
        System.out.println("Result: " + calc.divide(10, 2));  // 5
        System.out.println("Result: " + calc.divide(10, 0));  // 0
    }
}

Real-World Example: Input Validation

import java.util.Scanner;

public class InputValidator {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        while (true) {
            try {
                System.out.print("Enter a number: ");
                int number = Integer.parseInt(sc.nextLine());

                System.out.print("Divide by: ");
                int divisor = Integer.parseInt(sc.nextLine());

                int result = number / divisor;
                System.out.println("Result: " + result);
                break;

            } catch (NumberFormatException e) {
                System.out.println("Please enter valid numbers");
            } catch (ArithmeticException e) {
                System.out.println("Cannot divide by zero");
            }
        }

        sc.close();
    }
}

Best Practices

  1. Catch specific exceptions
  2. Handle appropriately - don’t ignore
  3. Log errors for debugging
  4. Don’t catch if you can’t handle
  5. Clean up resources in finally
  6. Don’t catch Error class
  7. Provide meaningful messages

Common Patterns

Pattern 1: Log and Continue

try {
    // operation
} catch (Exception e) {
    System.err.println("Error: " + e.getMessage());
    // Continue execution
}

Pattern 2: Log and Rethrow

try {
    // operation
} catch (Exception e) {
    System.err.println("Error occurred");
    throw e;  // Rethrow
}

Pattern 3: Default Value

int result;
try {
    result = riskyOperation();
} catch (Exception e) {
    result = 0;  // Default value
}

Quick Reference

// Single catch
try {
    // code
} catch (ExceptionType e) {
    // handle
}

// Multiple catch
try {
    // code
} catch (Exception1 e) {
    // handle 1
} catch (Exception2 e) {
    // handle 2
}

// Multi-catch (Java 7+)
try {
    // code
} catch (Exception1 | Exception2 e) {
    // handle both
}

// With finally
try {
    // code
} catch (Exception e) {
    // handle
} finally {
    // cleanup
}

// Exception methods
e.getMessage()        // error message
e.toString()          // exception details
e.printStackTrace()   // full trace

Common Mistakes

// ✗ Empty catch (bad practice)
try {
    // code
} catch (Exception e) {
    // Nothing - error hidden!
}

// ✗ Catching too general
try {
    // code
} catch (Exception e) {  // Too broad
    // ...
}

// ✗ Wrong order
try {
    // code
} catch (Exception e) {  // General first
    // ...
} catch (IOException e) {  // Unreachable!
    // ...
}

// ✓ Correct
try {
    // code
} catch (FileNotFoundException e) {
    System.out.println("File error: " + e.getMessage());
} catch (IOException e) {
    System.out.println("IO error: " + e.getMessage());
}

Exam Tips

Remember:

  1. catch handles exceptions
  2. Specific before general order
  3. Multiple catch blocks allowed
  4. Multi-catch with | (Java 7+)
  5. Exception object has useful methods
  6. Don’t ignore exceptions
  7. finally for cleanup
  8. Nested try-catch allowed
  9. Log errors properly
  10. Clean up resources

Common Questions:

  • How to catch exceptions?
  • Multiple catch blocks?
  • Order of catch blocks?
  • Multi-catch syntax?
  • Exception object methods?
  • Nested try-catch?
  • Best practices?
  • Common mistakes?
  • When to catch?
  • What not to catch?