相信大多数人在使用Java的时候,经常会使用到try-finally去关闭各种打开的资源,比如数据库连接,文件流等。于是,我们的代码经常就会像这个样子:
import java.io.BufferedReader;import java.io.FileReader;import java.io.IOException;public class ReadFile { public static void main(String[] args) { BufferedReader reader = null; String buffer = null; try { reader = new BufferedReader(new FileReader("src/testRead.txt")); do { buffer = reader.readLine(); System.out.println(buffer); } while (reader.read() != -1); } catch (IOException e) { e.printStackTrace(); } finally { try { reader.close(); } catch (IOException e) { e.printStackTrace(); } } }}
一个简单的Java获取文件读取操作。可是代码却冗长的像老太婆的裹脚布又长又臭:我们在finally中为了防止关闭reader的时候发生异常,不得不再加一层的try-catch操作来进行异常捕获。
还有一个更大的问题是,假如在buffer = reader.readLine()这句语句抛出了异常,而同时,在finally中的reader.close()语句也发生了异常,那么finally块中的异常信息就会覆盖掉reader.readLine()语句的异常信息。也就是说异常堆栈跟踪中没有第一个异常的记录,这可能会使实际系统中的调试变得非常复杂。虽然可以通过编写代码来抑制第二个异常而支持第一个异常,但是这会使得编写的人员异常痛苦,而且代码也会越来越长。
那么怎么解决这样的问题呢?让人高兴的是,在Java7中引入了try-with-resources语句,就是用来处理这个问题的,我们看看用try-with-resources后的代码:
import java.io.BufferedReader;import java.io.FileReader;import java.io.IOException;public class ReadFile { public static void main(String[] args) { String bufferSugar = null; try (BufferedReader readerSugar = new BufferedReader(new FileReader("src/testRead.txt"))) { bufferSugar = readerSugar.readLine(); System.out.println(bufferSugar); } catch (IOException e) { e.printStackTrace(); } }}
是不是简单了很多,主要的代码都用来处理业务逻辑而没有去过多的关心资源的关闭。而且,如果异常是由 readLine 调用和不可见的 close 抛出的,则后一个异常将被抑制,以支持前一个异常。实际上,还可能会抑制多个异常,以保留实际希望看到的异常。这些被抑制的异常不会仅仅被抛弃;它们会被打印在堆栈跟踪中,并标记它们被抑制。可以通过编程方式使用 getSuppressed 方法访问到它们。
那么try-with-resources做了什么让我们不再需要自己手动调用资源的close呢?用jad工具反编译看看源码:
import java.io.*;public class ReadFile{ public ReadFile(){} public static void main(String args[]) { String bufferSugar = null; Exception exception; exception = null; Object obj = null; BufferedReader readerSugar = new BufferedReader(new FileReader("src/testRead.txt")); bufferSugar = readerSugar.readLine(); System.out.println(bufferSugar); if(readerSugar != null) readerSugar.close(); break MISSING_BLOCK_LABEL_90; exception; if(readerSugar != null) readerSugar.close(); throw exception; Exception exception1; exception1; if(exception == null) exception = exception1; else if(exception != exception1) exception.addSuppressed(exception1); throw exception; IOException e; e; e.printStackTrace(); }}
可以看出try-with-resources为我们做了两件事:
- 添加了close
- try块里面和close函数都可能抛出异常,这里会将try块抛出的异常压缩成Suppressed Exceptions,可以调用Throwable.getSuppressed方法取出被抑制的异常
而try-with-resources就是Java7为我们提供的一个语法糖啦。
所以,今后如果有在用到try-finally去处理资源的开启关闭的时候,记得有一种更加方便的方式:try-with-resources。
参考: