Mastering Java Exception Handling: 13 Best Practices for Cleaner Code

This guide walks through common pitfalls and 13 practical best‑practice techniques for handling exceptions in Java, covering everything from avoiding ignored errors and using global handlers to proper logging, try‑with‑resources, custom exceptions, and avoiding exception‑driven control flow.

Su San Talks Tech
Su San Talks Tech
Su San Talks Tech
Mastering Java Exception Handling: 13 Best Practices for Cleaner Code

Hello everyone, happy 1024 Programmer's Day!

Preface

In daily development we often encounter exceptions such as NullPointerException, NumberFormatException, ClassCastException, and others. How can we handle these exceptions gracefully and write cleaner code?

1. Do Not Ignore Exceptions

Bad example:

Long id = null;
try {
    id = Long.parseLong(keyword);
} catch (NumberFormatException e) {
    // ignore exception
}

The code catches the exception but neither logs nor handles it, making troubleshooting difficult.

Good example:

Long id = null;
try {
    id = Long.parseLong(keyword);
} catch (NumberFormatException e) {
    log.info(String.format("keyword: {} conversion to Long failed, reason: {}", keyword, e));
}

Now the failure reason is recorded in the logs.

2. Use a Global Exception Handler

Instead of catching exceptions in every service method, delegate them to a centralized handler. In Spring Boot you can define a class annotated with @RestControllerAdvice and methods with @ExceptionHandler:

@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(Exception.class)
    public ApiResult handleException(Exception e) {
        if (e instanceof BusinessException) {
            BusinessException be = (BusinessException) e;
            log.info("Business exception occurred", e);
            return ApiResultUtil.error(be.getCode(), be.getMessage());
        }
        log.error("System exception occurred", e);
        return ApiResultUtil.error(HttpStatus.INTERNAL_SERVER_ERROR.value(), "Internal server error, please contact the administrator!");
    }
}

With this handler, individual try/catch blocks in controllers or services can be removed.

3. Catch Specific Exceptions

Bad example:

try {
    doSomething();
} catch (Exception e) {
    log.error("doSomething failed", e);
}

Better to catch the exact exceptions:

try {
    doSomething();
} catch (FileNotFoundException e) {
    log.error("doSomething failed, file not found", e);
} catch (IOException e) {
    log.error("doSomething failed, IO error", e);
}

4. Close IO Streams in a finally Block

Bad example (closing inside try):

try {
    FileInputStream fis = new FileInputStream(file);
    // read data
    fis.close();
} catch (IOException e) {
    log.error("Read file failed", e);
}

If an exception occurs before fis.close(), the stream remains open. Good example:

FileInputStream fis = null;
try {
    fis = new FileInputStream(file);
    // read data
} catch (IOException e) {
    log.error("Read file failed", e);
} finally {
    if (fis != null) {
        try { fis.close(); } catch (IOException e) { log.error("Failed to close stream", e); }
    }
}

5. Prefer try‑with‑resources

Since JDK 7, you can let the resource close automatically:

File file = new File("/tmp/1.txt");
try (FileInputStream fis = new FileInputStream(file)) {
    byte[] data = new byte[(int) file.length()];
    fis.read(data);
    for (byte b : data) { System.out.println(b); }
} catch (IOException e) {
    e.printStackTrace();
    log.error("Read file failed", e);
}

The FileInputStream implements AutoCloseable, so it is closed automatically.

6. Do Not Return from finally

Returning inside a finally block overrides any previous return value:

public int divide(int dividend, int divisor) {
    try {
        return dividend / divisor;
    } catch (ArithmeticException e) {
        // handle
    } finally {
        return -1; // overrides normal result
    }
}

Correct approach is to return only from try or catch blocks.

7. Avoid e.printStackTrace()

Printing stack traces to standard error can expose sensitive information in production. Use logging instead:

try {
    doSomething();
} catch (IOException e) {
    log.error("doSomething failed, reason:", e);
}

8. Log Detailed Exception Information

Do not log only e.getMessage(). Log the full exception:

try {
    double b = 1/0;
} catch (ArithmeticException e) {
    log.error("Processing failed, reason:", e);
}

This prints the stack trace and line number.

9. Do Not Catch and Immediately Rethrow

Catching an exception just to log it and then rethrowing leads to duplicate logs. Let the global handler log it once.

10. Prefer Standard Exceptions

Use built‑in exceptions like IllegalArgumentException instead of custom ones when they convey the same meaning.

11. Document Thrown Exceptions

Include @throws tags in method Javadoc to describe possible exceptions.

12. Do Not Use Exceptions for Flow Control

Replace exception‑driven logic with regular conditional checks, e.g., using a helper method to validate input before parsing.

13. Define Custom Exceptions When Needed

If business requirements demand, create custom exceptions with additional fields such as error code and message:

@AllArgsConstructor
@Data
public class BusinessException extends RuntimeException {
    private static final long serialVersionUID = -6735897190745766939L;
    private int code;
    private String message;
    public BusinessException() { super(); }
    public BusinessException(String message) {
        this.code = HttpStatus.INTERNAL_SERVER_ERROR.value();
        this.message = message;
    }
}

This custom exception can carry richer error information.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaException Handlingbest practicescode qualitySpringBoot
Su San Talks Tech
Written by

Su San Talks Tech

Su San, former staff at several leading tech companies, is a top creator on Juejin and a premium creator on CSDN, and runs the free coding practice site www.susan.net.cn.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.