java TWR是怎么优雅我们的代码的?

我们在编写IO代码的时候,有的时候真的是对对java IO那种模板化的代码感到厌倦,而且写出来的代码,很臃肿丑陋。像下面这样的代码:

   public void readFile(String filePath) {
        FileInputStream fis = null;
        InputStreamReader inReader = null;
        BufferedReader br = null;
        try {
            fis = new FileInputStream(filePath);
            inReader = new InputStreamReader(fis);
            br = new BufferedReader(inReader);
            for (String line; (line = br.readLine()) != null; ) {
                //TODO
            } 
        } catch (IOException e) {
            e.printStackTrace();
        } finally  {
            if (null != fis) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (null != inReader) {
                try {
                    inReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (null != br) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

真的是看花眼啊,尤其是那个finally块,太长了。而且有的时候,忘记关闭资源,导致资源被耗尽,程序出现异常,还得各种定位问题。

java1.7带来了一个新特性,即TWR(Try-With-Resource)语法,我们可以不用去管那finally块了,只需将上面的代码改写成这样即可。

    public void readFile(String filePath) {
        try (FileInputStream fis = new FileInputStream(filePath);
                InputStreamReader inReader = new InputStreamReader(fis);
                BufferedReader br = new BufferedReader(inReader);) {
            for (String line; (line = br.readLine()) != null; ) {
                //TODO
            } 
        } catch (IOException e) {
            e.printStackTrace();
        } 
    }

即,在try()括号内初始化IO变量。这样来看,代码一下子精简不少。我们再也不用关注那臃肿的finally块了。

那么java1.7是怎么做到的呢?我们将上面的代码,放到TWR.java源文件中,并import相应的类,然后在JDK1.7.0_80用javac编译一下,得到TWR.class文件。如图:

借助于IDEA,我们反编译了这份字节码文件,看看javac都为我们做了什么。

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;

public class TWR {
    public TWR() {
    }

    public void readFile(String var1) {
        try {
            FileInputStream var2 = new FileInputStream(var1);
            Throwable var3 = null;

            try {
                InputStreamReader var4 = new InputStreamReader(var2);
                Throwable var5 = null;

                try {
                    BufferedReader var6 = new BufferedReader(var4);
                    Throwable var7 = null;

                    try {
                        while(true) {
                            if (var6.readLine() != null) {
                                continue;
                            }
                        }
                    } catch (Throwable var54) {
                        var7 = var54;
                        throw var54;
                    } finally {
                        if (var6 != null) {
                            if (var7 != null) {
                                try {
                                    var6.close();
                                } catch (Throwable var53) {
                                    var7.addSuppressed(var53);
                                }
                            } else {
                                var6.close();
                            }
                        }

                    }
                } catch (Throwable var56) {
                    var5 = var56;
                    throw var56;
                } finally {
                    if (var4 != null) {
                        if (var5 != null) {
                            try {
                                var4.close();
                            } catch (Throwable var52) {
                                var5.addSuppressed(var52);
                            }
                        } else {
                            var4.close();
                        }
                    }

                }
            } catch (Throwable var58) {
                var3 = var58;
                throw var58;
            } finally {
                if (var2 != null) {
                    if (var3 != null) {
                        try {
                            var2.close();
                        } catch (Throwable var51) {
                            var3.addSuppressed(var51);
                        }
                    } else {
                        var2.close();
                    }
                }

            }
        } catch (IOException var60) {
            var60.printStackTrace();
        }

    }
}

通过这份反编译代码,我们知道了,原来是javac在编译的时候,悄悄地为我们加上了finally块,而且它的写法更加安全。

在java类库中,也有很多TWR的身影,像java.nio.file.Files类的readAllLines()方法:

代码截取自JDK_1.9.0.1的源码:

    public static List<String> readAllLines(Path path, Charset cs) throws IOException {
        try (BufferedReader reader = newBufferedReader(path, cs)) {
            List<String> result = new ArrayList<>();
            for (;;) {
                String line = reader.readLine();
                if (line == null)
                    break;
                result.add(line);
            }
            return result;
        }
    }

【总结】:TWR写法告诉了编译器javac,自动的为我们增加了资源关闭代码。

【问题】:如果不采用TWR写法,那么关闭顺序是怎么定的呢?

猜你喜欢

转载自blog.csdn.net/guohengcook/article/details/81268018
今日推荐