还在用try-finally中关闭各种资源,你不累吗?

255 阅读3分钟
原文链接: mp.weixin.qq.com

相信大多数人在使用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。

参考:

https://www.cnblogs.com/darrenqiao/p/9201357.html

强哥叨逼叨

叨逼叨编程、互联网的

见解和新鲜事