Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

There is no single Java compiler warning called “Java logging and exception rethrowing.” A warning near a catch, logging call, or throw is usually an IDE inspection or configured static-analysis rule, and its exact name determines what it expects. First note the full diagnostic, rule ID, analyzer, and version; then choose a fix based on what the code is meant to do.

Choose the fix that matches the catch block’s purpose

Code intent Preferred approach Watch for
Catch only to rethrow the same exception Remove the catch if it adds no behavior and the exception can propagate. The catch may be needed for cleanup, translation, recovery, or control flow.
Add context or change exception type Throw an appropriate new exception with the original as its cause. A new exception without the cause loses diagnostic information.
Recover or provide a fallback Catch, handle the failure, and return or continue as appropriate. Do not rethrow after handling unless propagation is part of the contract.
Cannot handle the failure locally Propagate it; log at the layer that handles it. Logging at several layers can duplicate stack traces.
Log and handle locally Pass the exception object to the logger. getMessage() is not the same as attaching the throwable.
Build an expensive diagnostic message Use parameterized or lazy logging, or a supported level guard. Expensive argument expressions can still run eagerly.

Remove a catch that only rethrows

A catch block with no work beyond throw e; often adds complexity without changing behavior. PMD’s Java design rules and IntelliJ’s CaughtExceptionImmediatelyRethrown inspection document this kind of pattern.

try {
    performWork();
} catch (IOException e) {
    throw e;
}

If the method already permits the exception to propagate, write:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
performWork();

Do not remove a catch that performs required cleanup, recovery, retry, exception translation, or adds useful context. If the only purpose is closing an AutoCloseable, try-with-resources is usually a better fit, provided it matches the project’s resource ownership and cleanup behavior.

Wrap an exception without losing its cause

When a layer needs to translate an exception or provide domain-specific context, create an appropriate exception and pass the original exception as its cause:

try {
    repository.load(id);
} catch (SQLException e) {
    throw new RepositoryException("Could not load record " + id, e);
}

The constructor taking a message and a Throwable preserves the original exception in the cause chain. Oracle’s chained exceptions tutorial describes this pattern. Avoid a wrapper that discards the cause:

catch (SQLException e) {
    throw new RepositoryException("Could not load record " + id);
}

PMD’s Java best-practices rules include PreserveStackTrace, which flags a new exception thrown from a catch when it does not refer to the caught exception. Its documented options include passing the original to the constructor or calling initCause. Do not wrap merely to quiet a warning; use an exception type that communicates the failure at the relevant API boundary, and catch only the range of exceptions the code genuinely handles.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Decide where a failure should be logged

Logging and rethrowing is not forbidden by Java, but it can produce duplicate reports when an upstream handler logs the same exception. If this layer cannot resolve the failure, propagation without logging is often clearer:

service.call();

If this layer owns the handling decision, log the failure and handle it rather than rethrowing it without a deliberate reason:

try {
    service.call();
} catch (ServiceException e) {
    logger.error("Could not complete the request", e);
    return fallback();
}

If the layer must translate the exception, preserve its cause and decide which layer owns the log event. A lower layer can still log a distinct event when it contributes independently useful operational information; the aim is to avoid repeating the same stack trace at every layer.

Attach the throwable to the log event

SLF4J

Use the exception-aware overload rather than converting the failure to text:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
logger.error("Could not complete the request", e);

The SLF4J Logger API documents error(String, Throwable), and the SLF4J FAQ explains supplying the exception as the throwable argument when its stack trace is needed. This does not attach the exception object:

logger.error("Request failed: " + e.getMessage());

For SLF4J 2’s fluent API, attach the cause explicitly:

logger.atError()
      .setCause(e)
      .log("Could not complete request for {}", requestId);

The LoggingEventBuilder API documents setCause(Throwable).

java.util.logging

The JDK logging API provides an overload that takes a level, message, and throwable:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
logger.log(Level.SEVERE, "Could not complete the request", e);

See the Java SE 25 Logger API. Overloads and level names differ among logging APIs, so use the exception-specific form documented for the framework in the project rather than assuming that every placeholder convention treats a final throwable the same way.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Address logging-performance warnings

PMD’s GuardLogStatement rule covers message construction or method calls performed even when a log level may be disabled. Parameterized logging can avoid eagerly building a concatenated message:

logger.debug("Loaded record " + recordId);

Prefer the parameterized form supported by the logger:

logger.debug("Loaded record {}", recordId);

Parameter substitution does not necessarily defer evaluation of the argument expression. If an argument is expensive to compute, use the framework’s lazy logging feature or an enabled-level check when appropriate. The supported forms vary by API; the SLF4J manual documents its parameterized and fluent logging options, while PMD’s best-practices rules describe alternatives to an explicit guard.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Check cleanup, retries, and exception behavior

Try-with-resources and suppressed exceptions

When a resource close fails while another exception is already being thrown, try-with-resources keeps the primary exception and records close failures as suppressed exceptions. Avoid replacing this with a finally-block throw that can mask the original failure. See Java SE 25’s Throwable API and the Java Language Specification section on try-with-resources.

Same-object rethrow

In Java, throw e; rethrows that exception object. The usual concern behind a rethrow-only warning is redundant catch logic, not a stack trace being reset. When creating a new exception, preserve the original as its cause if the original failure matters; Oracle explains the cause relationship in its chained exceptions tutorial.

Retries and recovery

A catch can be necessary when code retries an operation or supplies a fallback. Ensure the catch actually implements that behavior; if the failure remains unresolved, propagate it rather than silently treating it as handled. If a retry eventually fails, preserve the relevant exception information when translating or reporting that failure.

Verify the diagnostic before suppressing it

  1. Record the full warning text, rule ID, IDE or analyzer name, and version. Similar wording can refer to different checks.
  2. Open the rule documentation and compare its stated intent with this catch block’s actual behavior. PMD documents its distinct checks in its design rules and best-practices rules.
  3. Make the behavior clear in code: remove a redundant catch, preserve a cause when wrapping, log at the handling boundary, or attach the throwable to the event.
  4. If a warning conflicts with an intentional project convention, suppress it as narrowly as the tool allows and explain why the exception is intentional. IntelliJ’s inspection suppression documentation covers suppressing and re-enabling inspections; removing its suppression annotation or comment re-enables the inspection.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.