Java exception handling

Necessity

Exceptions are not only an error control mechanism, but also a communication medium. Developing exception specifications enables everyone to understand common concepts and use them in the same way, and improves code readability and api usability.

Before exception capture:

  1. Resource release/close put in finally or use try-with-resources;
  2. Specific exceptions that may be thrown are specified in the method declaration and described in the method notes document.

In exception capture:

  1. First catch the most specific exception;
  2. Do not capture Throwable, this will also capture JVM error errors, which may not be handled;

After exception capture:

  1. Once captured, exceptions cannot be swallowed silently, at least the exception log should be printed.
  2. When the print log or is encapsulated and thrown after capture, more specific exception information should be added;
  3. It is not possible to print the log and throw it directly after catching the exception, which results in two identical log messages being printed twice, which should be encapsulated as a custom exception and thrown after adding more details.
  4. When encapsulating a custom exception after capture, the original exception cannot be discarded. Set the original exception to cause before throwing it.

Release resource in finally or use try-with-resources

To ensure that resources are released accurately, prevent resources from being released due to business code exception process interruptions:

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);
    }
}

Method declarations specify specific exceptions that may be thrown

Use the most specific exception possible to declare a method:

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

Document exceptions

/**
 * This method does something extremely useful ...
 *
 * @param input
 * @throws MyBusinessException if ... happens
 */
public void doSomething(String input) throws MyBusinessException {
    ...
}

Bring description when throwing an exception

When throwing an exception, you need to describe the problem and related information as accurately as possible so that it can be read more easily, whether printed to the log or in a monitoring tool, so that you can better locate the specific error information, the severity of the error, and so on.

Catch the most specific exception first

When there are multiple catch blocks, only the first matched catch block can be executed in the capture order.

Do not capture Throwable

Throwable is the parent of all exceptions and errors. If catch has Throwable, it will not only catch all exceptions, but also errors.

Eror is a JVM error indicating that it cannot be recovered. So don't capture throwable unless absolutely certain or required to handle errors.

Do not ignore exceptions

There are often unexpected exceptions or uncertainties about whether the code here will change in the future, when the exception is caught and not enough error information is available to locate the problem. It is reasonable to record at least exceptional information.

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

Do not throw exceptions directly after logging

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

Throwing an exception directly after recording it will result in an exception outputting the same exception log multiple times. The correct way to do this is to wrap the exception as a custom exception and add more information before throwing it out:

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

Do not discard original exceptions when packaging exceptions

It is common to catch standard exceptions and wrap them as custom exceptions. This adds more specific exception information and enables exception handling.

It is important to note that when wrapping exceptions, be sure to set the original exception to cause(Exception has constructors that can be passed into cause). Otherwise, losing the original anomaly information makes it difficult to analyze the errors.

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

Reference resources:

Handling several practices of Exception is elegant and adopted by many teams!

Tags: Java source code

Posted on Tue, 23 Nov 2021 18:00:15 -0500 by vexx