Question 27 · Section 7

In what order should catch blocks be arranged?

catch blocks must go from more specific to more general:

Language versions: English Russian Ukrainian

Junior Level

Main rule: from specific to general

catch blocks must go from more specific to more general:

try {
    Files.readAllLines(Paths.get("file.txt"));
} catch (FileNotFoundException e) {
    // 1. Specific case first
    System.out.println("File not found");
} catch (IOException e) {
    // 2. More general next
    System.out.println("IO error");
} catch (Exception e) {
    // 3. Most general - at the end
    System.out.println("Unknown error");
}

Why

If you put the general catch first, it catches everything, and specific catch blocks never execute:

// Compilation error!
try {
    // code
} catch (Exception e) {
    // Catches everything, including IOException
} catch (IOException e) {
    // Never executes - code is unreachable
}

Compiler outputs: "exception IOException has already been caught".

“First match wins” mechanism at the compiler level

At compile time:

The javac compiler checks each catch block sequentially top to bottom (JLS 14.20). For each new catch it asks: “Is this catch’s type a subtype of any catch that was above?”

  • If yes - compiler issues an error, because code in this catch block is unreachable (unreachable code, JLS 14.21).
  • If no - catch is added to the class’s Exception Table.

This is a static check - compiler doesn’t allow compilation with wrong order. Therefore in properly compiled code the order is always correct.

At runtime (JVM):

Exception Table is an array of {from, to, target, type} entries. When an exception is thrown, JVM:

  1. Searches for the first entry where the type matches the exception (or its supertype).
  2. Jumps to target - address of the corresponding catch block.
  3. Remaining entries are ignored.

Therefore “first match” is literally the first matching entry in the Exception Table.

Simple rule

Arrange by inheritance hierarchy - from children to parents.

When NOT to follow the “specific to general” rule

  1. Never violate it - this rule is enforced by the compiler, reverse order won’t compile
  2. Multi-catch inside - order of types in catch (A | B e) doesn’t matter, because both types point to the same target in Exception Table
  3. Don’t catch Throwable in business logic - only at the system boundary
  4. Don’t put rare exceptions before frequent ones - if FileNotFoundException occurs 100x more often than EOFException, catch it first for micro-optimization of Exception Table search
  5. Don’t mix abstraction levels - don’t alternate business and infrastructure exceptions without logic

Caveat: Java 7+ multi-catch changes the approach to ordering

With the appearance of multi-catch in Java 7, the ordering question becomes less critical in some scenarios. If you have 3+ exceptions with identical handling, instead of:

// 3 catch blocks - order matters (FileNotFoundException before IOException)
catch (FileNotFoundException e) { handle(); }
catch (SQLException e) { handle(); }
catch (IOException e) { handle(); }

You can write:

// 1 catch block - order inside multi-catch does NOT matter
catch (FileNotFoundException | SQLException | IOException e) { handle(); }

Multi-catch removes the ordering problem, because all types are handled identically and point to one target in the Exception Table.

When catch block order does NOT matter

  1. All catch blocks handle identically - if each catch does log.error(e); throw new ServiceException(e);, order doesn’t affect the result. However in this case it’s better to use multi-catch.

  2. Exceptions are not related by inheritance - catch (SQLException e) and catch (NullPointerException e) have no common subtype. They never intersect, and order between them doesn’t affect correctness (though it may affect search performance).

  3. Multi-catch - inside catch (A | B e) the order of types doesn’t matter. Compiler generates separate entries in Exception Table, but they all point to one target.

  4. Single catch block - catch (Exception e) - nothing to order.


Middle Level

First Match Wins

JVM scans Exception Table top to bottom. First match captures control.

Arrangement strategy

1. Expected vs Exceptional: Catch the most frequent business exceptions (e.g., ValidationException) first - they’ll be at the start of the Exception Table.

2. Different handling:

@PostMapping("/orders")
public ResponseEntity<?> createOrder(@RequestBody OrderRequest req) {
    try {
        return ResponseEntity.ok(orderService.create(req));
    } catch (ValidationException e) {
        // 400 Bad Request - client error
        return ResponseEntity.badRequest().body(e.getMessage());
    } catch (ResourceNotFoundException e) {
        // 404 Not Found
        return ResponseEntity.notFound().build();
    } catch (DataAccessException e) {
        // 500 Server Error - our problem
        log.error("Database error processing order", e);
        return ResponseEntity.internalServerError().build();
    }
}

Multi-catch order

In catch (A | B e) the order within the block doesn’t matter:

catch (IOException | SQLException e) { }
catch (SQLException | IOException e) { }
// Same thing

But you still can’t combine parent and child.

Interaction with try-with-resources

Exceptions on automatic resource closing (close()) occur before reaching your catch blocks. Your catch may catch an exception from close() if there were no errors in the main try.


Senior Level

Exception Table and performance

Search in Exception Table - complexity O(n). In methods with dozens of catch blocks this can have a microscopic impact on performance. Place the most frequent exceptions first.

Handling Error

If you catch Throwable, you also catch Error (e.g., OutOfMemoryError):

// Rule: specific Exception above Throwable
try { ... }
catch (BusinessException e) { }      // Business errors
catch (DataAccessException e) { }    // Infrastructure
catch (Throwable t) { }              // Only at the end, at system boundary

Never do catch (Throwable t) in the middle of business logic - only at the outermost system boundaries.

Exception Hiding

Wrong order can “hide” an important error in a general log. Monitoring won’t see the difference between ValidationException and OutOfMemoryError.

Static Analysis

Use Checkstyle or Sonar to guarantee a consistent approach to exception catching hierarchy across the entire project.

Diagnostics

  • javap -c - shows Exception Table with jump priorities to catch labels
  • Metrics - count each exception type separately
  • Log Correlation - save Trace ID for all error types
  • Global Error Handler - @ControllerAdvice catches everything not caught locally

Interview Cheat Sheet

Must know:

  • Main rule: from specific to general - children before parents in Exception Table
  • Compiler won’t allow reverse order - error “exception X has already been caught”
  • JVM scans Exception Table top to bottom, first match captures control (first match wins)
  • Order within catch (A | B e) does NOT matter - all types point to one target
  • Exceptions not related by inheritance can be arranged in any order between themselves
  • Place the most frequent exceptions first for micro-optimization of search
  • catch (Throwable t) - only at system boundary, never in business logic

Frequent follow-up questions:

  • What happens if you mix up the order? - Compilation error, code won’t compile
  • Does order affect performance? - O(n) search, frequent exceptions first
  • When is order NOT important? - Multi-catch, non-inheritance-related types, single catch
  • Why do we catch Throwable only at the end? - Catches Error including OutOfMemoryError

Red flags (NOT to say):

  • “I put general catch first for convenience” - won’t compile
  • “Order in multi-catch matters” - no, all types -> one target
  • “I catch Throwable in the middle of business logic” - catches Error, state is unpredictable
  • “Catch order affects correctness of compiled code” - compiler guarantees correct order

Related topics:

  • [[24. Can you have multiple catch blocks for one try]] - multiple catches and first match wins
  • [[25. What is multi-catch (catching multiple exceptions)]] - multi-catch removes ordering problem
  • [[1. What is the difference between checked and unchecked exceptions]] - exception hierarchy
  • [[5. What is at the top of the exception hierarchy]] - Throwable and Error
  • [[19. Why you should not swallow exceptions (catch empty)]] - incorrect handling