您的代码调用InputStream.close()
或者OutputStream.close()
是一些高级代码,它们委托给较低级别InputStream
或OutputStream
类以执行一些高级计算。
是否抛出异常
关于做什么,你只有 3 个选择。
- 捕获并吞下异常,将其丢弃。
- 让它向上传播。
- 捕获异常,并抛出不同类型的异常。在这种情况下,您通常会使用链式异常。
最后两个选项相似,因为您的代码会引发异常。所以这个问题实际上是我的代码什么时候应该抛出异常这个问题的一个特例。在这种情况下,该问题的正确答案是:当且仅当替代方案是未能满足代码的后置条件或保持代码的不变量。后置条件指定了您的方法的用途。不变量指定类的特征。
因此,您需要问自己,close()
抛出异常是否会阻止您的方法执行应该执行的操作。
- 如果它不会阻止您的方法完成其工作,那么正确的做法是吞下异常。尽管很多人会告诉你。
- 如果
close()
throwing 确实阻止了您的方法完成其工作,并且该方法可能 throw IOException
,那么您什么也做不了,只是让异常向上传播。
- 如果
close()
阻止您的方法完成其工作,但该方法可能不会 throw IOException
,您必须捕获IOException
并重新抛出它作为不同的异常类,将 记录IOException
为引发异常的原因。
我不知道在什么情况下InputStream.close()
抛出异常会阻止计算成功。在您阅读完您感兴趣的任何数据后,该调用close()
自然会发生。
但是,输出流可以在内部(在 Java 代码中)或在较低级别(在操作系统中)缓冲要写入输出目的地的数据。OutputStream.close()
因此,在成功返回(不引发异常)之前,您无法确定对输出流的写入操作实际上是否产生了真正的输出。因此,您应该将抛出的异常视为OutputStream.close()
写入失败。
您的方法负责维护其不变量。close()
如果抛出异常,有时这将需要清理或回滚操作。即使您希望异常向上传播,您也应该将其代码放在catch
orfinally
子句中。IOException
如果您使用 catch 子句并且想要传播它,则必须重新抛出它。
是否记录异常
有些人会建议您记录异常。这几乎总是不好的建议。日志消息是程序用户界面的一部分。从根本上说,您必须始终问自己是否要记录任何内容,因为无用的措辞会分散阅读您的日志文件的用户的注意力和混淆(“用户”包括系统管理员)。记录的每条消息都应该用于某些有用的目的。每个都应该提供帮助用户做出决定的信息。
专门报告close()
失败的情况很少有用。它如何帮助用户做出决定?如果异常没有阻止您的方法完成其工作,则没有问题,用户无需执行任何操作。如果您的程序无法close()
流式传输,这是一个问题,用户可以做些什么来提供帮助?
低级代码通常根本不负责记录。相反,它执行抽象操作,通过抛出异常向程序的更高级别部分报告失败。关闭流的代码通常是相当低级别的,因此检测到该级别的代码close()
太低而无法进行任何日志记录。
失败的具体事实close()
很少有用。知道您的方法要执行的抽象操作失败是有用的。这可以通过让更高级别的代码捕获所有预期的异常并报告操作失败来完成,而不是让您的方法准确地报告“关闭失败”。