使用完流和读写器后,需要正确关闭它们。这可以通过调用 close() 方法来实现。不过这需要花点心思。请看这段代码:
// 输入流 InputStream input = new FileInputStream("C:\\Users\\Administrator\\Desktop\\input.txt"); int data = input.read(); while(data != -1) { // 对数据进行一些处理... doSomethingWithData(data); data = input.read(); } input.close(); // 关闭流
这段代码乍一看没什么问题。但如果在 doSomethingWithData() 方法中出现异常会怎样呢?没错!InputStream 永远不会关闭!
为了避免这种情况,你可以将代码重写成这样:
InputStream input = null; try { input = new FileInputStream("C:\\Users\\Administrator\\Desktop\\input.txt"); int data = input.read(); while(data != -1) { // 对数据进行一些处理... doSomethingWithData(data); data = input.read(); } } catch(IOException e) { // 对异常...比如记录日志,或者再次抛出等。 } finally { if(input != null) { input.close(); } }
请注意 InputStream 现在是如何在 finally 子句中关闭的。无论 try 块中发生了什么,finally 子句都会被执行。因此,InputStream 将始终关闭。
但是,如果 close() 抛出异常会怎样?比如说流已经关闭了?那么,要捕获这种情况,就必须把对 close() 的调用也包在 try-catch 块中,就像这样:
try { //... } catch(IOException e) { //... } finally { try{ if(input != null) { input.close(); } } catch(IOException e){ // 做点什么,或者忽略 } }
正确处理 InputStream(或 OutputStream)迭代的代码可能会很难看,正如你所看到的,一旦你也正确处理了异常,就会很难看。这种丑陋的异常处理代码遍布整个代码,反复出现,并不是一件好事。如果有人急于求成,跳过异常处理怎么办?
此外,假设 doSomethingWithData() 首先抛出了一个异常。第一个 catch 子句将捕获该异常,然后 finally 子句将尝试关闭 InputStream。但是,如果 input.close() 方法也抛出异常,会发生什么情况?这两个异常中的哪一个应该在调用栈中向上传播?
幸运的是,有一种方法可以解决这个问题。这个办法叫做 “异常处理模板”。创建一个异常处理模板,在使用后正确关闭数据流。该模板只需编写一次,并在整个代码中重复使用。简单易用。要了解更多信息,请访问 Java 中的异常处理模板。
从 Java 7 开始,Java 包含了一种新的异常处理机制,称为 “try with resources”。这种异常处理机制特别针对在使用需要在使用后正确关闭的资源(如 InputStream、OutputStream 等)时的异常处理。
一个简单示例:
package com.hxstrive.java_io.demo01; import java.io.FileReader; import java.io.Reader; /** * FileReader 示例 * @author hxstrive.com */ public class FileReaderDemo { public static void main(String[] args) { // try with resources try(Reader reader = new FileReader("C:\\Users\\Administrator\\Desktop\\input.txt")) { int data = reader.read(); while(data != -1){ char dataChar = (char) data; System.out.print(dataChar); data = reader.read(); } } catch (Exception e) { e.printStackTrace(); } } }
上述代码,当代码正常或异常退出 try-catch 后,JVM 会自动关闭 Reader 资源。