【问题标题】:Why is InputStream.close() declared to throw IOException?为什么 InputStream.close() 声明抛出 IOException?
【发布时间】:2013-12-22 20:46:09
【问题描述】:

java.io.InputStream.close() 方法被声明为抛出一个IOException。到底什么情况下会抛出这样的异常?

编辑:是的,我已经阅读了 javadoc。任何人都可以比“发生 I/O 错误时”更具体吗? 什么在关闭InputStream 时会发生 I/O 错误?

【问题讨论】:

  • 如果发生 I/O 错误。
  • 如果它已经关闭了?
  • @meriton 我想你会在 IOException 类而不是 InputStream 类 javadoc 中找到“可能发生什么 I/O 错误...”问题的答案。正如我在回答中提到的那样,我也希望它在 InputStream 中,但在查看 IOException 的所有子类时找不到它并且有我的“啊哈”时刻。
  • @Martinsos:java.io.Closable.close 的 JavaDoc 写道:如果流已经关闭,则调用此方法无效。

标签: java exception ioexception


【解决方案1】:

在从文件系统读取输入流的情况下,当文件系统本身在关闭期间更新文件上的上次访问时间元数据或其他一些元数据时,可能会引发错误。无论如何,这在实践中几乎从未发生过。

在从网络连接读取输入流的情况下,关闭错误更容易想象。网络套接字的正常关闭实际上涉及通过连接发送关闭请求(TCP/IP FIN 数据包)并等待另一端确认此关闭请求。 (事实上​​,连接的另一端依次发送关闭请求,关闭端确认。)因此,在套接字输入流的情况下,关闭操作实际上涉及通过连接发送流量,因此关闭可以因错误而失败。

请注意,在许多实现中,如果流已经关闭,close() 通常不会抛出IOException;它只是默默地失败再次关闭流。

【讨论】:

    【解决方案2】:

    我正在查看 Java 源代码,发现了一些有趣的东西,这表明了 IOException 的原因。 InputStream 是一个抽象类。因此,我们无法预测将关闭的输入类型,因此保持信息流动是件好事。

    使用该输入流的任何代码都需要能够抛出IOException,因为关闭输入流可能会失败。如果它失败了,任何使用实现的人都需要知道它,因为很有可能需要处理它。

    了解 Java 中异常结构的布局很重要。当然,每个例外都会扩展Exception。但是,还有更广泛的异常类别:java.lang.IOException 就是其中之一,涵盖了所有可能的输入/输出异常。当我们说存在 I/O 错误时,我们指的是属于 IOException 的任何内容。结果,许多例外都扩展了这一例外,例如FileNotFoundExceptionEOFException 等,因为有一个广泛的、总体的例外来管理这些非常重要。

    因此,任何 IO 类都需要能够在关闭时抛出任何的各种 IOException。 close() 因此必须抛出 IOException - 这使得它的实现也能够抛出 IOException 的任何扩展。这就是 close() 抛出 IOException 的原因 - 异常是继承的,您需要在关闭流时能够处理任何 IOException。


    这里有几个值得注意的场景:

    • 您不能关闭 IOStream 两次,尽管这样做通常不会引发异常
    • 内容变得无法访问(例如,磁盘已卸载)(close() 实际上对操作系统至关重要,因为它需要指示文件何时不再忙)
    • 通用源已关闭
    • IOException 的所有其他子类未涵盖的任何一般故障(例如 FileNotFoundException

    您可以通过运行Exception.getMessage() 来检查导致IOException 的原因。

    【讨论】:

    • 根据java.io.Closable.close 的JavaDoc,关闭一个关闭的流“没有效果”。至于其他原因,我看到它们在打开或读取流时如何发生,但在关闭时?
    • @mertion 嗯...是的。例如,如果您正在从磁盘读取,则关闭步骤是关键告诉操作系统不再使用该文件。如果程序无法做到这一点,则提醒程序是有意义的。
    • @meriton 我弄清楚了它存在的确切原因。请查看我的编辑。
    • 为什么告诉操作系统它可以释放文件描述符会失败?告诉程序这有什么好处?我的意思是,如果操作系统在询问时不关闭文件,程序可以做什么?
    • 我可能错了,但似乎抛出某种未经检查的异常对于close() 操作来说是更好的设计选择。
    【解决方案3】:

    最终必须进行底层关闭系统调用,例如在 Linux 上http://linux.die.net/man/2/close。记录该调用失败并显示EIO:“发生 I/O 错误。”所以原因是,底层文件系统close 调用可能会失败。

    【讨论】:

      【解决方案4】:

      我自己也想过这个问题,并且几年前对这个话题做了一些研究。这是我所知道的......

      如果您查看您提供的链接中的 javadoc,它清楚地指出“InputStream 的 close 方法什么都不做”,所以它不会抛出异常,对吗?但是再看看 IOException 的所有子类,你会发现在很多情况下 inputstream 的子类可能无法关闭流。所以我最好的猜测是这个异常是为子类设计的来使用它的。

      http://docs.oracle.com/javase/6/docs/api/java/io/IOException.html

      在某些情况下,这只不过是一种麻烦,而在其他情况下,它清楚地表明出了问题。这完全取决于您使用的输入流实现类型。

      【讨论】:

      • 顺便说一下,StackOverflow 在右栏中向我展示了这个,我认为这是一个非常相似主题的有趣讨论。看看这是否有助于解释...stackoverflow.com/questions/2766450/…
      猜你喜欢
      • 2021-03-05
      • 2012-01-13
      • 2012-09-21
      • 1970-01-01
      • 1970-01-01
      • 2013-04-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多