如何正确处理来自 close() 的 IOException

2022-09-02 13:58:58

Java I/O 类 、 、 和它们的各种子类都有一个可以抛出 .java.io.Readerjava.io.Writerjava.io.InputStreamjava.io.OutpuStreamclose()IOException

对于处理此类异常的正确方法,是否有任何共识?

我经常看到建议只是默默地忽略它们,但这感觉不对,至少在打开资源进行写入的情况下,关闭文件时出现问题可能意味着无法写入/发送未刷新的数据。

另一方面,在阅读资源时,我完全不清楚为什么会投掷以及如何处理它。close()

那么有什么标准的建议吗?

一个相关的问题是,close 是否曾经抛出过 IOException?,但这更多的是关于哪些实现真正抛出,而不是关于如何处理异常。


答案 1

记录它。

你不能真正做任何事情(例如编写一些从错误中恢复的代码),但它通常值得让别人知道它。

编辑:
经过进一步调查并阅读其他评论,我会说,如果您确实想处理它,那么您将不得不知道实现的细节。相反,您可能需要知道实现的详细信息,以决定是否需要处理它。

但实际上,我想不出任何流的例子,其中读取或写入可以正常工作而不会引发异常,但是关闭会。


答案 2

“忽略或只是记录通常是一个坏主意。这并没有回答这个问题。对于来自 close() 的 IOException,应该怎么做?只是重新推翻它只会把问题推得更远,在那里它甚至更难处理。

理论

直接回答您的问题:当此 IO 操作失败时,根据具体情况,您可能希望

  • 回滚更改(不要在磁盘上保留部分写入的文件,请将其删除)
  • 重试(可能在回滚后)
  • 忽略(并继续)
  • 中断当前任务(取消)

您通常可以在向用户显示的对话框中看到最后 3 个对话框。实际上,将选择委托给用户是一种可能性。

我认为重点是不要让系统处于不一致的状态。只是吞下一个关闭的异常可能会给你留下一个残缺的文件,导致以后的令人讨厌的错误。

实践

使用已检查的异常有点麻烦。出现以下选项:

  • 将它们转换为 ,扔掉它们,并让它们在足够高的级别上处理RuntimeException

  • 继续使用检查的异常并遭受语法痛苦

  • 使用更多可组合的错误处理结构,如IO monad(在Java中并不真正可用,至少没有尴尬的许多大括号(参见 http://apocalisp.wordpress.com/2008/05/16/thrower-functor/),并且没有全功率)

有关 IO monad 的更多信息

当您在 IO monad 上下文中返回结果时,您实际上并不是在执行 IO 操作,而是返回该操作的描述。为什么?这些操作有一个API,它们可以很好地组成(而不是投掷/尝试/捕获大屠杀)。

您可以决定是否要执行检查异常样式处理(使用或不安全的PerformIO'调用(实际执行组合的IO操作)。OptionValidation˙ in the return type), or dynamic style handling, with bracketing only on the final

要了解一些想法,请参阅我的Scala要点 http://gist.github.com/2709535,它托管了该方法。它返回资源处理的结果(如果可用)和未关闭的资源(如果关闭失败)。然后由用户决定如何处理这种不可关闭的资源。executeAndClose

它可以用/而不是如果需要一个/多个实际的例外来加强。ValidationValidationNELOption