00:00

Nested try Block in Java – Explained with Examples

A nested try block is a try-catch statement placed inside another try block (or inside a catch or finally block). It lets you handle different problems at different levels: an inner block deals with a narrow, local error, while an outer block deals with broader errors for the whole operation.

This tutorial shows how nested try blocks work, how an exception moves from an inner block to an outer one, how to use try-catch inside a catch block, and why extracting a method is often cleaner than deep nesting.

1. Syntax

Nested try syntax
try {                         // outer try
    statement1;
    try {                     // inner try
        statement2;
    } catch (ExceptionA e) {  // inner handler
        ...
    }
    statement3;
} catch (ExceptionB e) {      // outer handler
    ...
}

2. Handling Problems at Two Levels

Here each row of input contains two numbers to divide. The outer try handles badly formatted rows; the inner try handles only the division:

NestedTryBasics.java
public class NestedTryBasics {
    public static void main(String[] args) {
        String[] rows = {"10,2", "8,0", "x,4", "6"};

        for (String row : rows) {
            try {                                            // outer: problems with the row format
                String[] parts = row.split(",");
                int a = Integer.parseInt(parts[0]);
                int b = Integer.parseInt(parts[1]);          // may throw ArrayIndexOutOfBounds
                try {                                        // inner: problems with the calculation
                    System.out.println(row + " -> " + (a / b));
                } catch (ArithmeticException e) {
                    System.out.println(row + " -> division by zero, result set to 0");
                }
            } catch (NumberFormatException e) {
                System.out.println(row + " -> skipped, not a number");
            } catch (ArrayIndexOutOfBoundsException e) {
                System.out.println(row + " -> skipped, missing value");
            }
        }
    }
}
Output
10,2 -> 5
8,0 -> division by zero, result set to 0
x,4 -> skipped, not a number
6 -> skipped, missing value

A division by zero is handled inside, and processing continues with a default. Format problems are handled outside, and the whole row is skipped.

3. How Exceptions Move from Inner to Outer

When the inner try throws an exception:

  1. Java checks the inner catch blocks. If one matches, it handles the exception and execution continues after the inner statement.
  2. If none matches, the inner finally (if any) runs, and the exception passes to the outer try's catch blocks.
  3. If no outer catch matches either, the exception leaves the method.
InnerToOuter.java
public class InnerToOuter {
    public static void main(String[] args) {
        try {
            System.out.println("outer try starts");
            try {
                System.out.println("  inner try starts");
                Object text = "hello";
                Integer number = (Integer) text;            // ClassCastException
                System.out.println("  never printed " + number);
            } catch (ArithmeticException e) {               // does not match
                System.out.println("  inner catch (not used)");
            } finally {
                System.out.println("  inner finally runs anyway");
            }
            System.out.println("outer try continues? no, this is skipped");
        } catch (ClassCastException e) {                    // matches here
            System.out.println("outer catch handled " + e.getClass().getSimpleName());
        }
    }
}
Output
outer try starts
  inner try starts
  inner finally runs anyway
outer catch handled ClassCastException

The inner catch was for ArithmeticException, so the ClassCastException passed outward. The inner finally still ran first, and the rest of the outer try was skipped.

4. try-catch Inside a catch Block

A recovery action can fail too. Putting a try-catch inside the catch block handles a second failure without losing control of the program:

TryInsideCatch.java
public class TryInsideCatch {
    static void saveOrder(int id) {
        if (id % 2 == 0) throw new IllegalStateException("database unavailable");
        System.out.println("order " + id + " saved");
    }

    static void writeBackup(int id) {
        throw new IllegalStateException("backup disk full");
    }

    public static void main(String[] args) {
        for (int id : new int[] {1, 2}) {
            try {
                saveOrder(id);
            } catch (IllegalStateException e) {
                System.out.println("save failed: " + e.getMessage());
                try {                                  // a try-catch inside a catch block
                    writeBackup(id);
                } catch (IllegalStateException backupError) {
                    System.out.println("backup also failed: " + backupError.getMessage());
                }
            }
        }
    }
}
Output
order 1 saved
save failed: database unavailable
backup also failed: backup disk full

The same applies inside finally blocks, for example when closing a resource can itself throw an exception. Try-with-resources handles that case automatically.

5. A Cleaner Alternative: Extract a Method

Deeply nested try blocks are hard to read. Moving the inner try-catch into its own small method keeps each level simple and makes the inner logic reusable and testable:

ExtractMethod.java
public class ExtractMethod {
    // The inner try moved into its own method: easier to read and test
    static int safeDivide(int a, int b) {
        try {
            return a / b;
        } catch (ArithmeticException e) {
            return 0;
        }
    }

    public static void main(String[] args) {
        String[] rows = {"10,2", "8,0", "x,4"};
        for (String row : rows) {
            try {
                String[] p = row.split(",");
                System.out.println(row + " -> " + safeDivide(Integer.parseInt(p[0]), Integer.parseInt(p[1])));
            } catch (NumberFormatException e) {
                System.out.println(row + " -> skipped");
            }
        }
    }
}
Output
10,2 -> 5
8,0 -> 0
x,4 -> skipped

6. When to Use Nested try Blocks

  • Different parts of an operation need different recovery strategies.
  • An inner error is recoverable locally, but other errors should abort the whole operation.
  • Recovery or clean-up code in a catch or finally block can fail.

If you find yourself nesting more than two levels, extract methods, use multi-catch, or use try-with-resources instead.

7. Rules

  • Each try, at every level, needs its own catch or finally.
  • An exception handled by an inner catch does not reach the outer catches unless it is rethrown.
  • Inner finally blocks always run before control moves outward.
  • Variables declared in an inner block are not visible in outer blocks.

8. Summary

  • A nested try block is a try-catch inside another try, catch or finally block.
  • Inner handlers deal with local problems; unhandled exceptions move to the outer handlers.
  • Inner finally blocks run before the exception leaves them.
  • try-catch inside a catch block handles failures during recovery.
  • Prefer extracting methods over deep nesting.

Related Tutorials