相比之下,在 java 中,close
方法AutoCloseable
允许抛出任何异常,并强制调用者以某种方式处理它。但是,如果发生这种情况,调用者合理预期会做什么?这表明关闭资源的尝试以某种方式失败。那么用户是否必须在继续之前再次尝试关闭资源,也许有某种指数退避?
3 回答
的设计AutoCloseable
是 Java 已检查异常的结果。一些实现只需要能够抛出已检查的异常,因此throws Exception
是必需的。但是,实现应该声明抛出的更具体的类型(如果有的话):
虽然此接口方法声明为 throw
Exception
,但强烈建议实现者声明该close
方法的具体实现以抛出更具体的异常,或者如果关闭操作不会失败,则根本不抛出异常。
如果有办法避免它,你不应该抛出异常,但你不能总是避免它。例如,当关闭BufferedOutputStream
带有未刷新数据的 a 时,缓冲流有两个选项;忽略未写入的数据并关闭,或将其写入流,这可能会导致抛出异常。
因为 Java 的设计者能够using
在实现他们自己的 try-with-resources 功能之前看到 .NET 块中的清理异常处理出现的问题,所以他们能够对其进行改进。在 .NET 中,Dispose
块的作者经常面临一个令人不快的选择,要么吞下任何发生的异常,从而错误地让调用程序相信一切都很好,要么让异常以这样的方式渗出,Dispose
以消除任何异常的任何证据。以前的例外。幸运的是,Java 避免了这个问题。
如果 try-with-resources 块正常成功并且close
也正常成功,则外部代码认为一切正常。如果该部分发生异常try
但close
正常成功,则外部代码将看到 try-block 异常。如果try
正常完成但close
抛出异常,外部代码将看到close
异常。如果try
throws, but close
also throws, 那么外部代码将看到try
异常但也能够检索发生在其中的任何异常close
(并且如果多个嵌套的 try-with-resources 在 期间抛出异常close
,则所有抛出的异常都将可供外部代码使用)。
因此,与经常迫使作者扼杀由 .NET 引发的一些潜在严重异常的 .NET 设计不同Dispose
,Java 的设计倾向于在出现严重close
错误时抛出异常,以至于不应允许调用者相信一切都很好。
看起来每个涉及资源的操作,包括隐式 close() 调用,都被认为是 try{} 块的一部分。即使从技术/语法上考虑,资源也是在 {} 大括号之外提到的。
这意味着如果在 close() 期间抛出 IOException,它将被与您的 try 关联的某些 catch() 子句捕获(或者它会向上传播)。
关于可能需要抛出异常的原因:close() 可能会导致 flush(),flush() 可能会导致 write(),write() 可能会失败。