Java 如何正确处理close()中的IOException

Java 如何正确处理close()中的IOException,java,file-io,error-handling,ioexception,Java,File Io,Error Handling,Ioexception,Java I/O类Java.io.Reader,Java.io.Writer,Java.io.InputStream,Java.io.OutputStream及其各种子类都有一个close()方法,可以抛出IOException 对于处理此类例外情况的适当方式是否有任何共识 我经常看到一些建议,建议只是默默地忽略它们,但这感觉是错误的,至少在打开资源进行写入的情况下,关闭文件时出现问题可能意味着无法写入/发送未刷新的数据 另一方面,在阅读参考资料时,我完全不清楚为什么close()会抛出它,以及

Java I/O类
Java.io.Reader
Java.io.Writer
Java.io.InputStream
Java.io.OutputStream
及其各种子类都有一个
close()
方法,可以抛出
IOException

对于处理此类例外情况的适当方式是否有任何共识

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

另一方面,在阅读参考资料时,我完全不清楚为什么
close()
会抛出它,以及如何处理它

那么有什么标准的建议吗

一个相关的问题是,但这更多的是关于哪些实现真正抛出异常,而不是关于如何处理异常

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

编辑:
在进一步调查和阅读其他评论之后,我想说,如果你真的想处理它,那么你必须知道实现的细节。相反,您可能需要了解实现的细节,以决定是否需要处理它


但现实地说,我想不出任何流的例子,在这些流中,读或写操作可以正常工作而不引发异常,但是关闭会发生异常。

在关闭writer之前尝试使用flush。关闭时出现异常的主要原因是其他一些资源可能正在使用数据,或者编写器/读取器可能根本没有打开。在关闭资源之前,请尝试查找资源是否已打开。

首先,不要忘记将close()放在try-catch块的“finally”部分中。 其次,您可以用另一个try-catch异常包围close方法,并记录该异常。

在大多数情况下,close()实际上不会抛出IOException。以下是代码:

关闭网络资源的错误实际上应该属于某种类型的
运行时异常
,因为在程序连接到网络资源后,您可以断开网络资源的连接

您可以看到一些使用Google代码搜索的/Writer和Streams的各种实现示例。BufferedReader和PipedReader实际上都不会抛出IOException,因此我认为您不必担心它,这基本上是安全的。如果您真的担心,您可以检查正在使用的库的实现,看看是否需要担心异常

像前面提到的其他人一样,除了记录IOException之外,您不能对IOException做太多事情

毕竟,
finally
子句中的
try/catch块非常难看

编辑:

进一步的检查揭示了
IOException
的子类,如
InterruptedIOException
syncfailedeexception
、和
ObjectStreamException
,以及从中继承的类。因此,仅仅捕获一个
IOException
就太笼统了——除了记录信息之外,您不知道该如何处理它,因为它可能来自一系列错误

编辑2:

Urk,
BufferedReader
是一个糟糕的例子,因为它将
读取器
作为输入。我已将其更改为
InputStream.java


但是,有一个带有
InputStream
的层次结构,它取决于您要关闭的内容。例如,关闭
StringWriter
不起任何作用。javadocs对此很清楚。在这种情况下,您可以忽略IOException,因为您知道它永远不会生成。从技术上讲,您甚至不需要调用
close

/**
 * Closing a <tt>StringWriter</tt> has no effect. The methods in this
 * class can be called after the stream has been closed without generating
 * an <tt>IOException</tt>.
 */
public void close() throws IOException {
}
/**
*关闭StringWriter无效。本文中的方法
*类可以在流关闭后调用,而无需生成
*一个例外。
*/
public void close()引发IOException{
}

对于其他流,根据需要记录并处理异常。

通常,资源处理应如下所示:

final Resource resource = context.acquire();
try {
    use(resource);
} finally {
    resource.release();
}
release
引发异常的(不太可能)情况下,
use
引发的任何异常都将被丢弃。对于最接近接球手获胜的异常抛出,我没有任何问题。我相信JDK7(?)中的ARM块在这种情况下会做一些疯狂的事情,比如重新引用
use
异常,并附加
release
异常


如果使用executearound习惯用法,您可以将这些决定和潜在的混乱代码放在一个(或几个)位置。

忽略或仅仅记录日志通常是个坏主意。即使您确实无法从中恢复,也应始终以统一的方式处理I/O异常,以确保您的软件以统一的方式运行

我至少建议如下处理:

//store the first exception caught
IOException ioe = null;
Closeable resource = null;
try{
  resource = initializeResource();
  //perform I/O on resource here
}catch(IOException e){
  ioe = e;
}finally{
  if (resource != null){
    try{
      resource.close();
    }catch(IOException e){
      if(null == ioe){
        //this is the first exception
        ioe = e;
      }else{
        //There was already another exception, just log this one.
        log("There was another IOException during close. Details: ", e);
      }
    }
  }
}

if(null != ioe){
  //re-throw the exception to the caller
  throw ioe;
}
上面的内容非常详细,但效果很好,因为它更喜欢在资源I/O期间使用
IOException
,而不是在关闭期间使用,因为它更可能包含开发人员感兴趣的信息。当出现问题时,代码还将抛出一个
IOException
,因此您可以获得一个统一的行为

也许有更好的方法,但你明白了

理想情况下,您应该创建一个新的异常类型,允许存储同级异常,因此如果您得到两个
IOException
s,您可以同时存储它们


“忽略或仅仅记录日志通常是个坏主意。”这并没有回答问题。对于close()中的IOException,应该怎么做?仅仅是重复它只会把问题推得更高,甚至更难处理

理论

直接回答您的问题:当此IO操作失败时,根据具体情况,您可以
//store the first exception caught
IOException ioe = null;
Closeable resource = null;
try{
  resource = initializeResource();
  //perform I/O on resource here
}catch(IOException e){
  ioe = e;
}finally{
  if (resource != null){
    try{
      resource.close();
    }catch(IOException e){
      if(null == ioe){
        //this is the first exception
        ioe = e;
      }else{
        //There was already another exception, just log this one.
        log("There was another IOException during close. Details: ", e);
      }
    }
  }
}

if(null != ioe){
  //re-throw the exception to the caller
  throw ioe;
}