java中try-with-resources自动关闭io流

    在传统的输入输出流处理中,我们一般使用的结构如下所示,使用try - catch - finally结构捕获相关异常,最后不管是否有异常,我们都将流进行关闭处理:

try {
  //todo
} catch (IOException e) {
    log.error("read xxx fail,{}", e.getMessage())
} finally {
    try {
        if (in != null)in.close();
        if (out != null)out.close();
    } catch(Exception e) {
        log.error("stream close error,{}", e.getMessage())
    }
}

     在jdk1.7之后,推荐使用try() {} catch(IOException e){}的方式来处理io流,它可以自动关闭流。如下所示,是一个简单的按行读取文件内容的示例:

package com.xxx.io;

import java.io.FileNotFoundException;
import java.nio.file.Paths;
import java.util.Scanner;

public class ScannerDemo {
    public static void main(String[] args) {
        String filePath = "conf/test.txt";
        try (Scanner scanner = new Scanner(Paths.get(filePath).toFile())) {
            String line;
            while (scanner.hasNextLine()) {
                line = scanner.nextLine();
                System.out.println(line);
            }
        } catch (FileNotFoundException e) {
            System.out.println("read file error : " + e.getMessage());
        }
    }
}

    我们可以跟踪调试,当try(){}运行完毕的时候,就会进入scanner.close()方法体。 

     当使用了try(){}代码块之后,代码执行完毕,就可以进行流的自动关闭,比传统的方式简洁了不少。

    try()这部分,可以有多个语句,语句之间分号隔开,也可以同时包含输入流和输出流。最后执行完毕,统一关闭。

    有的文章提到,这是因为各种流实现AutoCloseable接口,并实现了close()方法,其实我们刚才的Scanner类,并没有实现AutoCloseable,仅仅是实现了Closeable接口。

    如下的示例,我们自定义一个类,实现Closeable接口,并覆盖close()方法。

package com.xxx.io;

import java.io.Closeable;

public class AutoCloseTest implements Closeable {
    @Override
    public void close() {
        System.out.println("closed");
    }

    public void work() {
        System.out.println("work");
    }

    public static void main(String[] args) {
        try (AutoCloseTest test = new AutoCloseTest()){
            test.work();
        }
    }
}

    运行程序,最终打印结果如下:

 

    同样,在执行try(){}之后,运行了流的close()方法。

    究其原因,其实是编译器编译这段代码之后,生成的代码其实和传统的try{}catch()finally{}结构类似:

 

    也就是说try(){}这段代码最后其实是try(){}catch()finally{}的一个简写形式。 好像瞬间感觉自动关闭流没那么神奇了。

    还有一个问题,这里代码块只有try(){}没有捕获异常,最后代码编译后却添加了一个捕获异常,如果我的代码里面有捕获异常,那岂不是会造成异常信息丢失?其实,不会,我们再来看刚才scanner的示例编译的结果:

    try(){}这里编译之后,如果捕获到异常,它会进行一个addSuppressed()操作,外层的try{}catch{}还是能捕获到这个异常。

猜你喜欢

转载自blog.csdn.net/feinifi/article/details/131075463