Master Java Exception Handling: 10 Best Practices Every Developer Should Follow

This article explains why exception handling in Java is challenging and presents ten practical best‑practice guidelines—including using finally or try‑with‑resources, declaring specific exceptions, documenting throws, providing clear messages, catching specific exceptions first, avoiding Throwable, logging properly, and preserving original causes—to write more robust and maintainable code.

Java Backend Technology
Java Backend Technology
Java Backend Technology
Master Java Exception Handling: 10 Best Practices Every Developer Should Follow

Handling exceptions in Java is not trivial; even experienced developers spend considerable time deciding which exceptions to handle and how.

Most development teams establish their own rules for exception handling, which often differ significantly.

The following are ten widely adopted best practices for handling exceptions in Java.

Clean resources in a finally block or use try‑with‑resources

A common mistake is closing resources like InputStream at the end of the try block. If an exception occurs, the close call is skipped, leading to resource leaks.

public void doNotCloseResourceInTry() {
    FileInputStream inputStream = null;
    try {
        File file = new File("./tmp.txt");
        inputStream = new FileInputStream(file);
        // use the inputStream to read a file
        // do NOT do this
        inputStream.close();
    } catch (FileNotFoundException e) {
        log.error(e);
    } catch (IOException e) {
        log.error(e);
    }
}

The proper approach is to place cleanup code in a finally block or use the try‑with‑resources statement.

public void closeResourceInFinally() {
    FileInputStream inputStream = null;
    try {
        File file = new File("./tmp.txt");
        inputStream = new FileInputStream(file);
        // use the inputStream to read a file
    } catch (FileNotFoundException e) {
        log.error(e);
    } finally {
        if (inputStream != null) {
            try {
                inputStream.close();
            } catch (IOException e) {
                log.error(e);
            }
        }
    }
}

public void automaticallyCloseResource() {
    File file = new File("./tmp.txt");
    try (FileInputStream inputStream = new FileInputStream(file)) {
        // use the inputStream to read a file
    } catch (FileNotFoundException e) {
        log.error(e);
    } catch (IOException e) {
        log.error(e);
    }
}

Declare the most specific exception

Use the most specific exception type in method signatures to improve readability.

public void doNotDoThis() throws Exception {
    ...
}

public void doThis() throws NumberFormatException {
    ...
}

For example, NumberFormatException clearly indicates a numeric formatting error.

Document thrown exceptions

When a method declares a thrown exception, add Javadoc with a @throws tag describing the scenario.

/**
 * Performs an operation.
 * @param input the input value
 * @throws MyBusinessException if a business rule is violated
 */
public void doSomething(String input) throws MyBusinessException {
    ...
}

Include descriptive information when throwing

Provide a concise description (one or two sentences) with the exception to aid logging and monitoring.

try {
    new Long("xyz");
} catch (NumberFormatException e) {
    log.error(e);
}
NumberFormatException

already conveys the error type; additional context should be brief.

Catch the most specific exception first

Catching a generic exception before a specific one prevents the specific handler from ever executing.

public void catchMostSpecificExceptionFirst() {
    try {
        doSomething("A message");
    } catch (NumberFormatException e) {
        log.error(e);
    } catch (IllegalArgumentException e) {
        log.error(e);
    }
}

Do not catch Throwable

Throwable

includes both Exception and Error. Catching it can swallow unrecoverable JVM errors; avoid it unless absolutely necessary.

public void doNotCatchThrowable() {
    try {
        // do something
    } catch (Throwable t) {
        // don't do this!
    }
}

Never ignore exceptions

Empty catch blocks hide problems. At a minimum, log the exception.

public void doNotIgnoreExceptions() {
    try {
        // do something
    } catch (NumberFormatException e) {
        // this will never happen
    }
}

public void logAnException() {
    try {
        // do something
    } catch (NumberFormatException e) {
        log.error("This should never happen: " + e);
    }
}

Do not log and re‑throw the same exception

Logging an exception and then re‑throwing it results in duplicate log entries.

try {
    new Long("xyz");
} catch (NumberFormatException e) {
    log.error(e);
    throw e;
}

When wrapping, preserve the original cause

Wrap standard exceptions in custom ones to add context, but always pass the original exception as the cause.

public void wrapException(String input) throws MyBusinessException {
    try {
        // do something
    } catch (NumberFormatException e) {
        throw new MyBusinessException("A message that describes the error.", e);
    }
}

Summary

Effective exception handling requires careful consideration of resource cleanup, specificity, documentation, messaging, ordering of catch blocks, and proper use of wrapping. Following these practices improves code readability, API usability, and overall system reliability.

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 practicesloggingtry-with-resources
Java Backend Technology
Written by

Java Backend Technology

Focus on Java-related technologies: SSM, Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading. Occasionally cover DevOps tools like Jenkins, Nexus, Docker, and ELK. Also share technical insights from time to time, committed to Java full-stack development!

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.