Rule S2221 checks that only thrown exceptions are caught using a catch
clause. In particular, catching Exception
(including RuntimeException
) when not required by the signature of methods called in the try
block is a code smell. This is perfectly fine if the exception were to be handled in the catch
block and any runtime error were suppressed.
However, the rule is also triggered if Exception
is caught and rethrown and nothing would be suppressed:
public class ErrorCatching {
public void whatever() throws CheckedException {
try {
compute();
} catch (Exception ex) {
try {
clean();
} catch (Exception suppressed) {
ex.addSuppressed(suppressed);
}
throw ex;
}
}
private void compute() throws CheckedException {
throw new CheckedException();
}
private void clean() {
throw new RuntimeException();
}
private static class CheckedException extends Exception { }
}
Here, for both catch
clauses an issue is raised. The outer exception is caught to do some necessary clean up, even in the case of runtime exceptions, and the actual exception handling is deferred to the caller. In the inner try-catch
a RuntimeException
could have been caught and no issue would have been created. In the case that clean()
would throw a checked exception, this wouldn’t work.
With this approach neither ex
nor suppressed
are lost, the callee performed some house keeping and the exceptions are handled at the appropriate layer.