When handling resources that require cleanup (like streams, connections, or transactions), ensure that errors during the cleanup phase don't overshadow or silently replace the original error. This applies to both try-with-resources and traditional try/finally blocks.
When handling resources that require cleanup (like streams, connections, or transactions), ensure that errors during the cleanup phase don’t overshadow or silently replace the original error. This applies to both try-with-resources and traditional try/finally blocks.
Key practices:
close()
should be suppressed or logged.Example of good error handling during cleanup:
// Handle errors in cleanup without losing original exception
Mono<Void> safeCleanupStep(String stepDescription, Mono<Void> stepMono) {
if (!logger.isDebugEnabled()) {
return stepMono.onErrorComplete();
}
return stepMono
.doOnError(e -> logger.debug(String.format("Error ignored during %s: %s",
stepDescription, e)))
.onErrorComplete();
}
// Usage in transaction cleanup
if (shouldDoCleanup) {
Mono<Void> step = safeCleanupStep("transaction cleanup",
cleanupOperation());
afterCleanup = afterCleanup.then(step);
}
When using traditional try/finally blocks, explicitly catch and log exceptions in the finally block:
InputStream in = null;
try {
in = resource.getInputStream();
// Process the stream...
return result;
}
catch (Exception ex) {
// Handle primary operation exception
throw ex;
}
finally {
if (in != null) {
try {
in.close();
}
catch (IOException ex) {
// Log but don't throw to avoid masking original exception
logger.warn("Error closing resource", ex);
}
}
}
Remember that try-with-resources doesn’t silently swallow exceptions from close() methods - they’re suppressed but attached to the primary exception, so choose this pattern carefully based on your error handling needs.
Enter the URL of a public GitHub repository