Java Multiple catch Blocks and Multi-catch Syntax

4 minute read

When a try block might throw different types of exceptions, you can handle each one separately with multiple catch blocks or combine unrelated ones with multi-catch syntax.


Multiple catch Blocks

try {
    String text = readFile("data.txt");
    int value = Integer.parseInt(text.trim());
    int result = 100 / value;

} catch (FileNotFoundException e) {
    System.out.println("File not found: " + e.getMessage());

} catch (NumberFormatException e) {
    System.out.println("Invalid number in file: " + e.getMessage());

} catch (ArithmeticException e) {
    System.out.println("Division error: " + e.getMessage());
}

Each catch handles a specific failure mode with a specific response.


Order Matters — Specific First

Java checks catch blocks top to bottom and enters the first matching one:

// ✅ CORRECT — specific before general
try {
    riskyOperation();
} catch (FileNotFoundException e) {
    // handles FileNotFoundException specifically
} catch (IOException e) {
    // handles all other IOExceptions
} catch (Exception e) {
    // fallback for anything else
}
// ❌ COMPILE ERROR — general before specific
try {
    riskyOperation();
} catch (IOException e) {
    // catches everything, including FileNotFoundException
} catch (FileNotFoundException e) {
    // unreachable — compiler error!
}

If a parent class appears before a child class, the child’s catch block is unreachable and the code won’t compile.


Multi-catch — Java 7+

Handle multiple unrelated exceptions the same way:

try {
    processData();
} catch (IOException | SQLException e) {
    logger.error("Data processing failed", e);
    throw new ServiceException("Processing error", e);
}

Rules for Multi-catch

Rule Explanation
Types separated by | Pipe symbol between exception types
No parent-child pairs IOException | FileNotFoundException — compile error
Variable is effectively final You cannot reassign e
Common parent type used e is the common type of all listed exceptions
// ❌ COMPILE ERROR — FileNotFoundException is a subclass of IOException
catch (IOException | FileNotFoundException e) { }

// ✅ CORRECT — unrelated exception types
catch (IOException | NumberFormatException e) { }

Why Is e Effectively Final?

catch (IOException | SQLException e) {
    // e could be either type at runtime
    // e = new IOException();  // ❌ COMPILE ERROR — cannot reassign
    logger.error("Error", e);
}

Since e might be different types, allowing reassignment could violate type safety.


Multi-catch vs Multiple catch — When to Use Each

Use Case Approach
Same handling for different exceptions Multi-catch (|)
Different handling per exception Multiple catch blocks
Need to access exception-specific methods Multiple catch blocks
Reducing boilerplate Multi-catch (|)

Same Handling → Multi-catch

// Before (repetitive)
catch (IOException e) {
    logAndAlert(e);
} catch (SQLException e) {
    logAndAlert(e);
}

// After (clean)
catch (IOException | SQLException e) {
    logAndAlert(e);
}

Different Handling → Multiple catch

catch (FileNotFoundException e) {
    useDefaultConfig();          // specific recovery
} catch (IOException e) {
    throw new ServiceException("IO failure", e);  // different response
}

Combining Both

try {
    loadAndProcess(filePath);

} catch (FileNotFoundException e) {
    // Specific handling
    System.out.println("File not found, creating default...");
    createDefaultFile(filePath);

} catch (IOException | ParseException e) {
    // Same handling for these two
    logger.error("Processing failed: " + e.getMessage());
    throw new DataException("Cannot process " + filePath, e);

} catch (Exception e) {
    // Catch-all fallback
    logger.error("Unexpected error", e);
    throw e;
}

Accessing Exception-Specific Methods

With multi-catch, you can only access methods from the common parent:

catch (IOException | SQLException e) {
    e.getMessage();       // ✅ Defined in Throwable
    e.getErrorCode();     // ❌ Only on SQLException
}

If you need exception-specific methods, use separate catch blocks:

catch (SQLException e) {
    int code = e.getErrorCode();    // ✅ SQLException-specific
    String state = e.getSQLState(); // ✅ SQLException-specific
} catch (IOException e) {
    // handle differently
}

Pattern: Catch, Log, Rethrow

try {
    return orderService.process(order);

} catch (ValidationException e) {
    logger.warn("Validation failed for order {}: {}", order.getId(), e.getMessage());
    throw e;  // let caller handle

} catch (PaymentException | InventoryException e) {
    logger.error("Order processing failed for {}", order.getId(), e);
    throw new OrderFailedException("Cannot process order", e);

} catch (Exception e) {
    logger.error("Unexpected error processing order {}", order.getId(), e);
    throw e;
}

Pattern: Fallback Chain

public Config loadConfig() {
    try {
        return loadFromFile("config.yml");
    } catch (FileNotFoundException e) {
        logger.info("Config file not found, trying environment");
    }

    try {
        return loadFromEnvironment();
    } catch (ConfigException e) {
        logger.info("Environment config not found, using defaults");
    }

    return Config.defaults();
}

Common Mistakes

Mistake Problem Fix
Parent before child Compile error (unreachable) Specific first
Related types in multi-catch Compile error Use only unrelated types
Catching Exception first Catches everything Put last or remove
Empty catch blocks Silent failures Log and rethrow
Too many catch blocks Hard to read Group with multi-catch, extract methods
Reassigning e in multi-catch Compile error e is effectively final

Key Takeaways

  1. Order catch blocks from most specific to most general — compiler enforces this.
  2. Use multi-catch (catch (A | B e)) for unrelated exceptions with identical handling.
  3. Multi-catch variable is effectively final — you can’t reassign it.
  4. Multi-catch types must be unrelated — no parent-child pairs.
  5. Use separate catches when you need exception-specific methods or different handling logic.

What’s Next?

Next: try-with-resources — automatic resource management, AutoCloseable, and suppressed exceptions.

Updated: