Java IO:异常处理

时间:2020-01-09 10:36:04  来源:igfitidea点击:

使用流和读取器/写入器时,需要正确关闭它们。这是通过调用close()方法完成的。不过,这需要一点思考。看下面的代码:

InputStream input = new FileInputStream("c:\data\input-text.txt");

int data = input.read();
while(data != -1) {
  //do something with data...
  doSomethingWithData(data);

  data = input.read();
}
input.close();

乍一看,这段代码看起来还不错。但是,如果从doSomethingWithData()方法内部抛出异常,会发生什么情况呢?这是正确的! InputStream永远不会关闭!

为了避免这种情况,我们可以将代码重写为此:

InputStream input = null;

try{
  input = new FileInputStream("c:\data\input-text.txt");

  int data = input.read();
  while(data != -1) {
      //do something with data...
      doSomethingWithData(data);

      data = input.read();
  }
}catch(IOException e){
  //do something with e... log, perhaps rethrow etc.
} finally {
  if(input != null) input.close();
}

注意,如何在finally子句中关闭" InputStream"。无论try块内发生了什么,都将执行finally子句。因此," InputStream"将始终关闭。

但是,如果close()抛出异常怎么办?说流已经关闭了吗?好了,要解决这种情况,我们也必须将对close()的调用也包装在try-catch块中,如下所示:

} finally {
  try{
    if(input != null) input.close();
  } catch(IOException e){
    //do something, or ignore.
  }
}

一旦正确地处理了异常,则正确处理" InputStream"(或者OutputStream)迭代的代码就可能很难看。这种丑陋的异常处理代码并不是特别好,因为它已经遍及整个代码,并一遍又一遍地重复。如果有人急着走开一个角落并跳过异常处理该怎么办?

此外,想象一下,首先从doSomethingWithData()抛出异常。第一个catch子句将捕获该异常,然后finally子句将尝试关闭InputStream。但是,如果input.close()方法也抛出异常,该怎么办?应当在调用堆栈中传播这两个异常中的哪一个?

幸运的是,有办法解决这个问题。该解决方案称为"异常处理模板"。创建一个异常处理模板,该模板在使用后正确关闭流。该模板只编写一次,并在整个代码中重复使用。漂亮又简单。要了解更多信息,请转到Java中的异常处理模板。

Java 7的Java IO异常处理

从Java 7开始,Java包含一种新的异常处理机制,称为"尝试使用资源"。当我们使用的资源在使用后需要正确关闭时,例如InputStreamOutputStream等,此异常处理机制特别针对处理异常处理。