AutoCloseable的close方法抛出异常是否有意义?应如何处理?

时间:2014-10-20 06:56:08

标签: java c# exception idisposable autocloseable

在C#中,在Dispose的{​​{1}}方法中抛出异常是considered错误practice

相比之下,在java中,IDisposable的{​​{1}}方法允许抛出任何异常并强制调用者以某种方式处理它。但如果发生这种情况,合理预期的调用者会怎样做?这表明以某种方式关闭资源的尝试失败了。那么用户在继续之前是否必须尝试再次关闭资源,可能是某种指数退避?

3 个答案:

答案 0 :(得分:1)

AutoCloseable的设计是Java检查异常的结果。有些实现只需要能够抛出已检查的异常,因此需要throws Exception。但是,implementations should declare more specific types thrown(如果有的话):

  

虽然声明此接口方法抛出Exception,但实施者强烈鼓励声明close方法的具体实现以抛出更具体的异常,或者抛出no如果关闭操作不能失败,则完全是异常。

如果有办法避免异常,你不应该抛出异常,但你不能总是避免它。例如,当使用未刷新的数据关闭{​​{3}}时,缓冲的流有两个选项;忽略未写入的数据并关闭或将其写入流,这可能导致异常被抛出。

答案 1 :(得分:1)

因为Java的设计人员能够在实现他们自己的try-with-resources功能之前看到.NET的using块中的清理 - 异常处理引起的问题,所以他们能够改进它。在.NET中,Dispose块的作者在吞下任何发生的异常,从而错误地让调用程序认为一切正常,或让异常从Dispose中渗透出来之间经常面临令人不快的选择。以这种方式消除任何先前例外的任何证据。幸运的是,Java避免了这个问题。

如果try-with-resources块正常成功并且close也正常成功,则外部代码会正常查看所有内容。如果try部分发生异常但close正常成功,则外部代码将看到try-block异常。如果try正常完成但close抛出,则外部代码将看到close异常。如果try抛出,但close也抛出,那么外部代码将看到try异常,但也能够检索close内发生的任何异常(如果多个嵌套的try-with-resources在close期间抛出异常,所有抛出的异常都可用于外部代码。)

因此,与.NET设计不同,它常常迫使作者扼杀Dispose引发的一些潜在严重的异常,Java的设计有利于close在任何时候充足的情况下抛出异常不应该让来电者相信一切都很好。

答案 2 :(得分:0)

看起来涉及资源的每个操作(包括隐式close()调用)都被视为try {}块的一部分。即使在技术/语法上思考,资源也会在{}括号之外提到。

这意味着如果在close()期间抛出IOException,它将被与你的try相关联的一些catch()子句捕获(或者它将向上传播)。

关于原因为什么可能需要抛出异常:close()可能导致flush(),flush()可能导致write(),而write()可能会失败。