如何正确且优雅地关闭IO

269 阅读1分钟

常规处理

常见的操作便是IO流这样的close操作:

public static void throwException(){
        File file = null;
        FileInputStream fis = null;
        try{
            file = new File("abc.txt");
            //可能抛出FileNotFoundException
            fis = new FileInputStream(file);
            fis.read();
        }catch(FileNotFoundException e){
            System.out.println("file not found");
            e.printStackTrace();
        }catch(IOException e){
            e.printStackTrace();
        } finally{
            try {
                if(fis != null){ 
                    fis.close(); 
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

正确处理

但是在Java核心技术书中,作者建议在finally块中尽量不要使用会抛出异常的资源回收语句。

并且你按照上述写法,在代码扫描时会提示"a throw statement in a finally block makes the control flow hard to understand",也就是这里的close操作尽量不要出现异常,可是有些资源回收语句确实会抛出异常,此时应该怎么做呢?

我们可以观察到close操作抛出的异常是IOException,而前面的文件读取流也catch了该异常,所以我们可以将两个异常归并到一起,然后代码就变成这样了:

public static void throwException(){
        File file = null;
        FileInputStream fis = null;
        try{
            try {
                file = new File("abc.txt");
                //可能抛出FileNotFoundException
                fis = new FileInputStream(file);
                fis.read();
            }  finally {
                if(fis != null){
                    fis.close();
                }
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

正确且优雅地处理

在 Java 7 以及后续版本中,支持 try-with-resources,任何实现 java.lang.AutoCloseable 接口的类,包括 java.io.Closeable 的实现类,都可以通过 try-with-resources 来关闭。

public class Main  implements AutoCloseable{
    public static void main(String[] args) {
        try (Main main = new Main()) {
            System.out.println("你俊哥帅不帅");

            int i = 1/0;
        } catch (Exception e) {
            System.out.println("报错");
        }finally {
            System.out.println("帅");
        }
    }
    @Override
    public void close() throws Exception {
        System.out.println("关闭");
    }
}

此时查看控制台,是先在try代码块中执行了close方法,然后再走的catch和finally。

你俊哥帅不帅
关闭
报错
帅

我知道很多人都知道try-with-resources怎么用,但是关于它与常规处理的区别应该知道。