In C#, it is considered bad practice to throw exceptions in the Dispose
method of an IDisposable
.
By contrast, in java the close
method of AutoCloseable
allows any Exception whatsoever to be thrown and forces the caller to handle it somehow. But what is the caller reasonably expected to do if this happens? This suggests that the attempt to close the resource failed somehow. So does the user have to try to close the resource again before continuing, perhaps with some sort of exponential backoff?
The design of
AutoCloseable
is a result of Java's checked exceptions. Some implementations simply have to be able to throw checked exceptions, and sothrows Exception
is needed. However, implementations should declare more specific types thrown (if any):You shouldn't throw exceptions if there's a way of avoiding it, but you can't always avoid it. For example, when closing a
BufferedOutputStream
with unflushed data, the buffered stream has two options; ignoring the unwritten data and close, or writing it to the stream, which can cause exceptions to be thrown.Because Java's designers were able to see the issues that arose with cleanup-exception handling in .NET's
using
blocks before implementing their own try-with-resources feature, they were able to improve upon it. In .NET, the author of aDispose
block is often faced with an unpleasant choice between swallowing any exceptions which occur, thus erroneously letting the calling program believe everything is fine, or letting exceptions percolating out fromDispose
in such fashion as to obliterating any evidence of any previous exception. Fortunately, Java avoids that issue.If a try-with-resources block succeeds normally and the
close
also succeeds normally, then the outside code sees everything as normal. If an exception occurs in thetry
portion but theclose
succeeds normally, the outside code will see the try-block exception. If thetry
completes normally but theclose
throws, the outside code will see theclose
exception. And iftry
throws, butclose
also throws, then outside code will see thetry
exception but also be able to retrieve any exception that occurred withinclose
(and if multiple nested try-with-resources throw exceptions duringclose
, all thrown exceptions will be available to the outside code).Consequently, unlike the .NET design which often compels authors to stifle some potentially-serious exceptions thrown by
Dispose
, Java's design favors havingclose
throw an exception any time something goes sufficiently wrong that the caller shouldn't be allowed to believe that everything's fine.It looks like every operation involving the resources, including the implicit close() invocation, is considered part of the try{} block. Even thought technically/syntactically, the resources are mentioned outside the {} braces.
Meaning that if an IOException gets thrown during the close(), it will get caught by some catch() clause associated with your try (or it will propagate up).
About the reason why exceptions might need to be thrown : close() might cause flush(), flush() might cause write()s, and write()s might fail.