When handling a caught exception, two mandatory informations should be either logged, or present in a rethrown exception:
The following code snippet illustrates this rule:
try { /* ... */ } catch (Exception e) { LOGGER.info("context"); } // Non-Compliant - exception is lost try { /* ... */ } catch (Exception e) { LOGGER.info(e); } // Non-Compliant - context is required try { /* ... */ } catch (Exception e) { LOGGER.info(e.getMessage()); } // Non-Compliant - exception is lost (only message is preserved) try { /* ... */ } catch (Exception e) { LOGGER.info("context", e); } // Compliant try { /* ... */ } catch (Exception e) { // Non-Compliant - exception is lost throw new RuntimeException("context"); } try { /* ... */ } catch (Exception e) { // Compliant throw new RuntimeException("context", e); }
When all instances of a general exception must be handled, but some specific ones not, propagation must be used. Propagation is allowed by this rule.
For example, the following code logs all Exception
exceptions which are not RuntimeException
.
All RuntimeException
exceptions are propagated.
try { /* ... */ } catch (RuntimeException e) { // Compliant - propagation of the specific exception throw e; } catch (Exception e) { // Compliant - catching of the general exception LOGGER.error("...", e); }
Conversion of checked exceptions into unchecked exceptions to ease propagation of checked exceptions is also allowed by this rule.
try { /* ... */ } catch (IOException e) { // Compliant - propagation of checked exception by encapsulating it into an unchecked exception throw new MyRuntimeException(e); }