🏠 Home β€Ί Exception Handling β€Ί Exception Chaining and Return Statement Flow
Card 5 of 5
Next β†’
EXCEPTION HANDLING

Exception Chaining and Return Statement Flow

Key Rule: Exceptions thrown in catch blocks are NOT caught by subsequent catch blocks in the same try-catch structure. Only exceptions from the try block can be caught.

πŸ“š Exception Hierarchy Reminder:

java.lang.Throwable
β”œβ”€β”€ java.lang.Error (unchecked - JVM errors, don't catch)
└── java.lang.Exception
    β”œβ”€β”€ java.lang.RuntimeException (unchecked - programming errors)
    β”‚   β”œβ”€β”€ IllegalArgumentException
    β”‚   β”œβ”€β”€ NullPointerException  
    β”‚   β”œβ”€β”€ IndexOutOfBoundsException
    β”‚   └── IllegalStateException
    └── Checked Exceptions (must handle or declare)
        β”œβ”€β”€ IOException
        β”œβ”€β”€ SQLException
        β”œβ”€β”€ FileNotFoundException (extends IOException)
        └── ClassNotFoundException

Exception Classification Rules:

  • Checked Exception: Any exception that extends java.lang.Exception but is NOT a subclass of java.lang.RuntimeException
  • Unchecked Exception: Any exception that extends java.lang.RuntimeException (or java.lang.Error)
  • Checked exceptions must be handled with try-catch OR declared with throws
  • Unchecked exceptions can be handled but don’t have to be
public class FamilyReunion {
    public static void main(String[] args) {
        try {
            callGrandpa();  // This will throw an exception from TRY block
        } catch (IndexOutOfBoundsException father) {
            System.out.println("Father");           // Step 2: Catches exception from try block
            throw new NullPointerException();       // Step 3: Throws NEW exception from CATCH block
        } catch (NullPointerException mother) {
            System.out.println("Mother");           // ❌ WON'T EXECUTE! Exception not from try block
            return;                                 
        } catch (Exception grandma) {
            System.out.println("Grandma");          // ❌ WON'T EXECUTE! Exception not from try block
        } finally {
            System.out.println("Sister");           // Step 4: Always executes
        }
        System.out.println("FAMILY_GATHERING");    // ❌ WON'T EXECUTE! NullPointerException propagates
    }
    
    static void callGrandpa() {
        System.out.println("Grandpa speaks");      // Step 1: Always executes first
        throw new IndexOutOfBoundsException("Grandpa is grumpy!");
    }
}

// Output:
// Grandpa speaks
// Father  
// Sister
// Exception in thread "main" java.lang.NullPointerException

Step-by-Step Execution Flow:

// Detailed execution breakdown:
public class FamilyReunion {
    public static void main(String[] args) {
        try {
            callGrandpa();                          // Step 1: Call method - throws IndexOutOfBoundsException
        } catch (IndexOutOfBoundsException father) {
            System.out.println("Father");           // Step 2: Catches exception FROM TRY BLOCK
            throw new NullPointerException();       // Step 3: NEW exception FROM CATCH BLOCK
        } catch (NullPointerException mother) {     // ❌ CANNOT catch exceptions from catch blocks!
            System.out.println("Mother");           // NEVER executes - exception not from try block
            return;                                 
        } catch (Exception grandma) {               // ❌ CANNOT catch exceptions from catch blocks!
            System.out.println("Grandma");          // NEVER executes - exception not from try block  
        } finally {
            System.out.println("Sister");           // Step 4: Always executes before exception propagates
        }
        System.out.println("FAMILY_GATHERING");    // NEVER executes - uncaught exception terminates method
    }
    
    static void callGrandpa() {
        System.out.println("Grandpa speaks");      // Step 1a: Method execution
        throw new IndexOutOfBoundsException("Grandpa is grumpy!");  // Step 1b: Exception FROM TRY BLOCK
    }
}

🚨 Critical Concept: Only exceptions thrown in the TRY block can be caught by catch blocks!

Exception Source Matters:

try {
    throw new IOException("From try block");     // βœ… CAN be caught by catch blocks below
} catch (IOException e) {
    System.out.println("Caught from try");      // βœ… Executes - exception from try block
    throw new SQLException("From catch block"); // ❌ CANNOT be caught by catch blocks below  
} catch (SQLException e) {
    System.out.println("Caught from catch");    // ❌ NEVER executes - exception from catch block
} catch (Exception e) {
    System.out.println("Caught anything");      // ❌ NEVER executes - exception from catch block
}
// SQLException propagates up - uncaught!

Key Exception Catching Rules:

βœ… Exceptions that CAN be caught:

try {
    throw new RuntimeException("From try block");     // βœ… From try block
    methodThatThrows();                               // βœ… From method called in try block  
} catch (RuntimeException e) {
    // Will catch exceptions from try block
}

❌ Exceptions that CANNOT be caught:

try {
    normalMethod(); // No exception from try block
} catch (IOException e) {
    throw new SQLException("From catch block");       // ❌ From catch block - won't be caught
} catch (SQLException e) {
    // NEVER executes - SQLException came from catch block
} finally {
    throw new IllegalStateException("From finally");  // ❌ From finally block - won't be caught  
}

Nested Try-Catch Example:

// To catch exceptions from catch blocks, you need NESTED try-catch:
try {
    try {
        throw new IOException("Original problem");
    } catch (IOException e) {
        System.out.println("Caught original");
        throw new SQLException("New problem");        // This gets thrown to outer try
    }
} catch (SQLException e) {                           // βœ… This CAN catch it - different try block!
    System.out.println("Caught from inner catch");
}

πŸ’‘ Learning Tips:

  • Try block rule: β€œOnly try block exceptions are catchable” - catch blocks can’t catch exceptions from other catch blocks
  • Finally guarantee: β€œFinally runs then exception propagates” - finally executes but doesn’t catch exceptions
  • Propagation path: β€œUp and out” - uncaught exceptions from catch/finally blocks propagate to calling method
  • Nested solution: β€œTry within try” - use nested try-catch to handle exceptions from catch blocks

Common Exam Traps:

  1. Catch block exceptions - Thinking subsequent catch blocks will handle exceptions thrown in earlier catch blocks
  2. Finally block exceptions - Assuming finally can catch its own exceptions
  3. Exception propagation - Not realizing uncaught exceptions terminate the method
  4. Nested try confusion - Not understanding when you need nested try-catch structures

Q: Can a catch block catch an exception thrown by another catch block in the same try-catch structure?
A: No! Only exceptions thrown in the try block can be caught by catch blocks. Exceptions from catch blocks propagate up uncaught.