• 【JDK8】try-with-resources & AutoClosable


    针对流的使用和关闭:

    1)以前的写法:在finally不断try/finally进行资源的close操作

    BufferedInputStream bin = null;
            BufferedOutputStream bout = null;
            try {
                bin = new BufferedInputStream(new FileInputStream(new File("test.txt")));
                bout = new BufferedOutputStream(new FileOutputStream(new File("out.txt")));
                int b;
                while ((b = bin.read()) != -1) {
                    bout.write(b);
                }
            }
            catch (IOException e) {
                e.printStackTrace();
            }
            finally {
                if (bin != null) {
                    try {
                        bin.close();
                    }
                    catch (IOException e) {
                        e.printStackTrace();
                    }
                    finally {
                        if (bout != null) {
                            try {
                                bout.close();
                            }
                            catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
            }

    2)JDK8的写法

    public static void main(String[] args) {
            try (BufferedInputStream bin = new BufferedInputStream(new FileInputStream(new File("test.txt")));
                 BufferedOutputStream bout = new BufferedOutputStream(new FileOutputStream(new File("out.txt")))) {
                int b;
                while ((b = bin.read()) != -1) {
                    bout.write(b);
                }
            }
            catch (IOException e) {
                e.printStackTrace();
            }
        }

    背后的原因探究:try-with-resources 要求关闭的资源必须实现AutoCloseable接口

    Test1:基础测试

    public class Connection implements AutoCloseable {
    
        public void doTask() throws Exception {
            System.out.println("Connection doTask");
        }
    
        @Override
        public void close() throws Exception {
            System.out.println("Connection close()");
        }
    }

    调用的写法

    public class TryWithResource {
        public static void main(String[] args) {
            try (Connection conn = new Connection()) {
                conn.doTask();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    执行结果:

    Connection doTask
    Connection close()

    反编译的结果:自动生成了之前手写的try-catch-finally复杂逻辑

    public class TryWithResource {
        public TryWithResource() {
        }
    
        public static void main(String[] args) {
            try {
                Connection conn = new Connection();
                Throwable var2 = null;
    
                try {
                    conn.doTask();
                } catch (Throwable var12) {
                    var2 = var12;
                    throw var12;
                } finally {
                    if (conn != null) {
                        if (var2 != null) {
                            try {
                                conn.close();
                            } catch (Throwable var11) {
                                var2.addSuppressed(var11);
                            }
                        } else {
                            conn.close();
                        }
                    }
    
                }
            } catch (Exception var14) {
                var14.printStackTrace();
            }
    
        }
    }

    Test2:异常测试,Connection主动抛出异常

    public class Connection implements AutoCloseable {
    
        public void doTask() throws Exception {
            throw new Exception("doTask()");
        }
    
        @Override
        public void close() throws Exception {
            throw new Exception("close()");
        }
    }

    测试结果:可以抛出出问题地方

    原因是反编译时 var2.addSuppressed(var11) 作用(上面反编译结果红色字体部分)


    注意:在使用try-with-resource的过程中,一定需要了解资源的close方法内部的实现逻辑。否则还是可能会导致资源泄露。

     public static void main(String[] args) {
            try (FileInputStream fin = new FileInputStream(new File("input.txt"));
                    GZIPOutputStream out = new GZIPOutputStream(new FileOutputStream(new File("out.txt")))) {
                byte[] buffer = new byte[4096];
                int read;
                while ((read = fin.read(buffer)) != -1) {
                    out.write(buffer, 0, read);
                }
            }
            catch (IOException e) {
                e.printStackTrace();
            }
        }

    因为采用了装饰器模式,在调用GZIPOutputStream::close可能发生异常,而无法继续调用FileOutputStream::close方法

    正确做法:应该在try-with-resource中单独声明最底层的资源,保证对应的close方法一定能够被调用。

     public static void main(String[] args) {
            try (FileInputStream fin = new FileInputStream(new File("input.txt"));
                    FileOutputStream fout = new FileOutputStream(new File("out.txt"));
                    GZIPOutputStream out = new GZIPOutputStream(fout)) {
                byte[] buffer = new byte[4096];
                int read;
                while ((read = fin.read(buffer)) != -1) {
                    out.write(buffer, 0, read);
                }
            }
            catch (IOException e) {
                e.printStackTrace();
            }
        }
  • 相关阅读:
    spring boot 上传文件大小限制
    axios全局配置
    springboot 时间类型配置
    mybatis 全查 分页 模糊查询一体
    Vue响应式原理底层代码模拟实现
    浅谈vue响应式原理及发布订阅模式和观察者模式
    Vue Router的原理及history模式源码实现
    Vue路由之Hash模式和history模式的区别及History模式的解决办法
    webpack4.X之complier方法的实现及make前流程回顾
    webpack4.X之EntryOptionPlugin流程书写
  • 原文地址:https://www.cnblogs.com/clarino/p/12925788.html
Copyright © 2020-2023  润新知