问题
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?
回答1:
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.
回答2:
The design of AutoCloseable
is a result of Java's checked exceptions. Some implementations simply have to be able to throw checked exceptions, and so throws Exception
is needed. However, implementations should declare more specific types thrown (if any):
While this interface method is declared to throw
Exception
, implementers are strongly encouraged to declare concrete implementations of theclose
method to throw more specific exceptions, or to throw no exception at all if the close operation cannot fail.
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.
回答3:
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 a Dispose
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 from Dispose
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 the try
portion but the close
succeeds normally, the outside code will see the try-block exception. If the try
completes normally but the close
throws, the outside code will see the close
exception. And if try
throws, but close
also throws, then outside code will see the try
exception but also be able to retrieve any exception that occurred within close
(and if multiple nested try-with-resources throw exceptions during close
, 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 having close
throw an exception any time something goes sufficiently wrong that the caller shouldn't be allowed to believe that everything's fine.
来源:https://stackoverflow.com/questions/26459988/is-it-meaningful-for-autocloseables-close-method-to-throw-an-exception-how-sho