CodeGym /Courses /JAVA 25 SELF /Advanced exception handling and best practices

Advanced exception handling and best practices

JAVA 25 SELF
Level 24 , Lesson 3
Available

1. Multiple catch: handling different exceptions

In real programs, the same block of code can throw different types of exceptions. For example, when reading a file you might get a FileNotFoundException or an IOException, and when parsing data — a NumberFormatException. To handle each situation correctly, Java allows several consecutive catch blocks.

Syntax

try {
    // dangerous operations
} catch (FileNotFoundException e) {
    System.out.println("File not found: " + e.getMessage());
} catch (IOException e) {
    System.out.println("I/O error: " + e.getMessage());
} catch (NumberFormatException e) {
    System.out.println("Invalid number format: " + e.getMessage());
}

Important:
catch blocks must go from more specific to more general! If you write catch (Exception e) first, all the other blocks become unreachable and the compiler will report an error.

Why is this important?

  • Specific handling: You can react differently to different errors (for example, suggest choosing another file or retrying input).
  • Readability: The code becomes clearer — it’s visible which errors are expected and how they’re handled.

2. catch with multiple types (multi-catch)

Sometimes different exceptions need the same handling. For example, you might want to simply print an error message or log it, regardless of whether it was a file read error or a number conversion error.

Since Java 7, the multi-catch syntax lets you combine several exception types in one block:

try {
    // dangerous operation
} catch (IOException | NumberFormatException e) {
    System.out.println("Error processing file or number: " + e.getMessage());
}

How it works:

  • Use a vertical bar (|) to list exception types.
  • The variable e will have the most general common superclass type (usually Exception).
  • Inside the block you cannot assign a new value to e — it is implicitly final.

Example:

try {
    BufferedReader reader = new BufferedReader(new FileReader("numbers.txt"));
    String line = reader.readLine();
    int number = Integer.parseInt(line);
    System.out.println("Number: " + number);
    reader.close();
} catch (IOException | NumberFormatException e) {
    System.out.println("Error: " + e.getMessage());
}

3. Best practices for exception handling

Do not suppress exceptions

Bad:

try {
    // something dangerous
} catch (Exception e) {
    // do nothing!
}

Why is this bad?
An empty catch block “swallows” the error — you lose information about the cause of the failure, and the program becomes hard to debug.

Better: at least print a message or log the error.

catch (Exception e) {
    e.printStackTrace();
}

If you cannot handle the exception — rethrow it:

catch (IOException e) {
    throw e; // or throw new RuntimeException(e);
}

Throw the most specific exceptions

If you’re writing your own methods or APIs, always throw the most specific exceptions, not just Exception or RuntimeException. This makes your code and API clearer to other developers.

Example:

public void withdraw(double amount) throws InsufficientFundsException {
    if (amount > balance) {
        throw new InsufficientFundsException("Insufficient funds");
    }
    // ...
}

Do not use exceptions for control flow

Exceptions are meant for exceptional situations — that is, errors that should not happen during normal program execution. Do not use them for regular logic (for example, to exit a loop or check conditions).

Bad:

try {
    while (true) {
        String line = reader.readLine();
        if (line == null) break;
        // process the line
    }
} catch (Exception e) {
    // using an exception to exit the loop — bad!
}

Good:

String line;
while ((line = reader.readLine()) != null) {
    // process the line
}

4. Practical examples

Example: handle different errors differently

try {
    BufferedReader reader = new BufferedReader(new FileReader("data.txt"));
    String line = reader.readLine();
    int number = Integer.parseInt(line);
    System.out.println("Number: " + number);
    reader.close();
} catch (FileNotFoundException e) {
    System.out.println("File not found!");
} catch (IOException e) {
    System.out.println("File read error!");
} catch (NumberFormatException e) {
    System.out.println("Not a number in the file!");
}

Example: multi-catch for identical handling

try {
    // something dangerous
} catch (IOException | NumberFormatException e) {
    System.out.println("Error: " + e.getMessage());
}

5. Important nuances and common mistakes

Mistake #1: Incorrect order of catch blocks. More specific exceptions should come first, and then the general ones. Otherwise, execution will never reach the broad block.

Mistake #2: Using related types in a multi-catch. For example, catch (IOException | Exception e) will not compile because IOException extends Exception.

Mistake #3: Trying to modify variable e in a multi-catch. In this case e is final — you cannot assign a new value to it.

Mistake #4: Empty catch blocks. Ignoring errors leads to “silent” bugs. At a minimum, print a message or log the exception.

Mistake #5: Catching all Exception indiscriminately. Using catch (Exception e) hides real problems and makes debugging harder. It’s better to catch only expected exceptions.

1
Task
JAVA 25 SELF, level 24, lesson 3
Locked
Financial Report: Precise Diagnosis of Data Issues
Financial Report: Precise Diagnosis of Data Issues
1
Task
JAVA 25 SELF, level 24, lesson 3
Locked
Game Settings: Unified Response to Load Failures
Game Settings: Unified Response to Load Failures
1
Task
JAVA 25 SELF, level 24, lesson 3
Locked
Secret Archive: Access Priority to Confidential Data
Secret Archive: Access Priority to Confidential Data
1
Task
JAVA 25 SELF, level 24, lesson 3
Locked
Logging service: No error should be lost!
Logging service: No error should be lost!
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION