Master error handling to build robust and fault-tolerant Java applications
Java distinguishes between errors and exceptions, both of which are subclasses of Throwable.
Feature | Errors | Exceptions |
---|---|---|
Type | Unrecoverable | Recoverable |
Examples | OutOfMemoryError, StackOverflowError | IOException, SQLException, NullPointerException |
Handling | Should not be caught or handled | Should be caught and handled |
Package | java.lang.Error | java.lang.Exception |
Important: Errors indicate serious problems that a reasonable application should not try to catch, while exceptions indicate conditions that an application might want to catch and handle.
Java provides five keywords for exception handling: try, catch, finally, throw, and throws.
public class ExceptionDemo { public static void main(String[] args) { try { // Code that may throw an exception int result = divide(10, 0); System.out.println("Result: " + result); } catch (ArithmeticException e) { // Handle the exception System.out.println("Error: " + e.getMessage()); } finally { // Always executed System.out.println("Finally block executed"); } } public static int divide(int a, int b) { return a / b; } }
public class ThrowExample { public static void main(String[] args) { try { checkAge(15); } catch (ArithmeticException e) { System.out.println("Exception: " + e.getMessage()); } } // Method declares it may throw an exception public static void checkAge(int age) throws ArithmeticException { if (age < 18) { // Throw an exception throw new ArithmeticException("Access denied - You must be at least 18 years old"); } else { System.out.println("Access granted"); } } }
Java provides a rich hierarchy of exception classes in the java.lang package.
Exception | Description | Type |
---|---|---|
NullPointerException | Attempt to use null where an object is required | Unchecked |
ArrayIndexOutOfBoundsException | Access array with illegal index | Unchecked |
ArithmeticException | Arithmetic error (divide by zero) | Unchecked |
IOException | I/O operation failure | Checked |
SQLException | Database access error | Checked |
ClassNotFoundException | Class not found | Checked |
Checked vs Unchecked: Checked exceptions must be declared or handled, while unchecked exceptions (RuntimeException and its subclasses) do not require explicit handling.
public class MultipleCatch { public static void main(String[] args) { try { int[] arr = new int[5]; arr[10] = 50; // ArrayIndexOutOfBoundsException } catch (ArrayIndexOutOfBoundsException e) { System.out.println("Array index error: " + e.getMessage()); } catch (ArithmeticException e) { System.out.println("Arithmetic error: " + e.getMessage()); } catch (Exception e) { System.out.println("General exception: " + e.getMessage()); } } }
You can create your own exception classes to represent specific error conditions in your application.
// Custom exception class class InsufficientFundsException extends Exception { private double amount; public InsufficientFundsException(double amount) { super("Insufficient funds: " + amount); this.amount = amount; } public double getAmount() { return amount; } } class BankAccount { private double balance; public BankAccount(double balance) { this.balance = balance; } public void withdraw(double amount) throws InsufficientFundsException { if (amount > balance) { throw new InsufficientFundsException(amount - balance); } balance -= amount; System.out.println("Withdrawn: $" + amount); } } public class CustomExceptionDemo { public static void main(String[] args) { BankAccount account = new BankAccount(500); try { account.withdraw(100); account.withdraw(600); } catch (InsufficientFundsException e) { System.out.println("Error: " + e.getMessage()); System.out.println("You need $" + e.getAmount() + " more"); } } }
Best Practice: Custom exceptions should extend Exception for checked exceptions or RuntimeException for unchecked exceptions. Provide meaningful error messages and additional context where appropriate.
Exception propagation refers to the process where an exception is passed from method to method up the call stack until it's caught.
public class ExceptionPropagation { public static void main(String[] args) { try { methodA(); } catch (Exception e) { System.out.println("Exception handled in main: " + e.getMessage()); } } static void methodA() { System.out.println("In methodA"); methodB(); } static void methodB() { System.out.println("In methodB"); methodC(); } static void methodC() { System.out.println("In methodC"); // This will cause an exception int result = 10 / 0; System.out.println("Result: " + result); } }
import java.io.*; public class ThrowsPropagation { public static void main(String[] args) { try { readFile(); } catch (IOException e) { System.out.println("File error: " + e.getMessage()); } } // Propagate exception using throws static void readFile() throws IOException { FileReader file = new FileReader("nonexistent.txt"); BufferedReader reader = new BufferedReader(file); System.out.println(reader.readLine()); reader.close(); } }