try-with-resource 关闭资源分析

环境说明

要求: java 7 版本以上
测试环境: 1.8.0_102

Closeable

首先自己建一个 MyCloseable 实现 java.io.Closeable,在关闭资源时打印一句话:”关闭资源”

public class MyCloseable implements Closeable {
    @Override
    public void close() throws IOException {
        System.out.println("关闭资源");
    }
}

测试

main 源码

新建测试类App ,看看这段源码反编译后做了什么


public class App {
    public static void main(String[] args) {
        try (MyCloseable myCloseable = new MyCloseable()) {
            throw new RuntimeException("exception");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

main 反编译内容

public class App {
    public App() {
    }

    public static void main(String[] args) {
        try {
            MyCloseable myCloseable = new MyCloseable();
            Throwable var2 = null;

            try {

            } catch (Throwable var11) {
                var2 = var11;
                throw var11;
            } finally {
                if (myCloseable != null) {
                    if (var2 != null) {
                        try {
                            myCloseable.close();
                        } catch (Throwable var10) {
                            var2.addSuppressed(var10);
                        }
                    } else {
                        myCloseable.close();
                    }
                }

            }
        } catch (Exception var13) {
            var13.printStackTrace();
        }
    }
}

可以看出来 事实上 try-with-esource 实际上是java语法糖,它自己内部做了几个处理
1. 首先 new MyCloseable
2. 运行用户代码
3. 判断closeable 是否为空
- 为空: 什么也不做
- 不为空: 判断用户代码区是否有异常
- 没有异常: 执行MyCloseable里面的close
- 有异常: 执行MyCloseable里面的close,如果close发生异常就用用户的异常加上close的异常然后抛出
4. 执行用户的异常处理

四个可能的流程

完全没有异常

源码

 public class App {
     public static void main(String[] args) {
         try (MyCloseable myCloseable = new MyCloseable()) {
             System.out.println("完全没有异常");
         } catch (Exception e) {
             e.printStackTrace();
             System.out.println("用户异常处理");
         }
     }
 }

反编译

public class App {
    public App() {
    }

    public static void main(String[] args) {
        try {
            MyCloseable myCloseable = new MyCloseable(); // 1
            Throwable var2 = null; 

            try {
                System.out.println("完全没有异常"); // 2
            } catch (Throwable var12) {
                var2 = var12;
                throw var12;
            } finally {
                if (myCloseable != null) { // 3
                    if (var2 != null) { // 4
                        try {
                            myCloseable.close(); // 5
                        } catch (Throwable var11) {
                            var2.addSuppressed(var11);
                        }
                    } else {
                        myCloseable.close();
                    }
                }

            }
        } catch (Exception var14) {
            var14.printStackTrace();
            System.out.println("用户异常处理");
        }

    }
}

public class MyCloseable implements Closeable {
    @Override
    public void close() throws IOException {
        System.out.println("关闭资源");
    }
}

完全没有异常的情况下,执行完用户代码就做 Closeable为空判断和用户代码异常判断

最后执行关闭资源

用户代码有异常,close没异常

反编译

public class App {
    public App() {
    }

    public static void main(String[] args) {
        try {
            MyCloseable myCloseable = new MyCloseable(); // 1
            Throwable var2 = null; 

            try {
                throw new RuntimeException("用户代码异常"); // 2
            } catch (Throwable var12) {
                var2 = var12; 
                throw var12; // 3  // 7
            } finally {
                if (myCloseable != null) { // 4
                    if (var2 != null) {  // 5
                        try {
                            myCloseable.close();  // 6
                        } catch (Throwable var11) {
                            var2.addSuppressed(var11);
                        }
                    } else {
                        myCloseable.close();
                    }
                }

            }
        } catch (Exception var14) {
            var14.printStackTrace(); // 8
            System.out.println("用户异常处理");
        }

    }
}

public class MyCloseable implements Closeable {
    @Override
    public void close() throws IOException {
        System.out.println("关闭资源");
    }
}

当用户代码有异常的时候,整体流程就麻烦了一些,接下来一步一步分析
1. MyCloseable myCloseable = new MyCloseable(); 创建的时候也在用户异常捕获里面,所以不用担心new对象发生异常不处理
2. 用户代码发生异常
3. 准备抛出异常,但是发现有finally代码区
4. 执行finally代码区, 判断 myCloseable 为空 (当前不为空)
5. 判断用户代码区是否有异常 (当前有异常)
6. 关闭资源
7. 抛出异常
8. 执行用户异常处理

用户代码没有异常,close有异常

反编译

public class App {
    public App() {
    }

    public static void main(String[] args) {
        try {
            MyCloseable myCloseable = new MyCloseable(); // 1
            Throwable var2 = null; 

            try {
               System.out.println("用户资源没有异常"); //2
            } catch (Throwable var12) {
                var2 = var12; 
                throw var12;
            } finally {
                if (myCloseable != null) { // 3
                    if (var2 != null) {  // 4
                        try {
                            myCloseable.close();  
                        } catch (Throwable var11) {
                            var2.addSuppressed(var11); 
                        }
                    } else {
                        myCloseable.close(); // 5
                    }
                }

            }
        } catch (Exception var14) {  // 6
            var14.printStackTrace(); 
            System.out.println("用户异常处理");
        }

    }
}

public class MyCloseable implements Closeable {
    @Override
    public void close() throws IOException {
        throw new RuntimeException("关闭资源异常"); 

    }
}

关闭资源异常流程分析
1. MyCloseable myCloseable = new MyCloseable(); 创建的时候也在用户异常捕获里面,所以不用担心new对象发生异常不处理
2. 用户资源没有异常
3. 执行finally代码区, 判断 myCloseable 为空 (当前不为空)
4. 判断用户代码区是否有异常 (当前没有异常)
5. 关闭资源(else 代码块),发生异常,被最外层的用户异常所捕获
6. 执行用户异常处理

用户代码有异常,close有异常

反编译

public class App {
    public App() {
    }

    public static void main(String[] args) {
        try {
            MyCloseable myCloseable = new MyCloseable(); // 1
            Throwable var2 = null; 

            try {
               throw new RuntimeException("用户代码异常"); // 2
            } catch (Throwable var12) {
                var2 = var12; 
                throw var12; // 3   // 8
            } finally {
                if (myCloseable != null) {  // 4
                    if (var2 != null) {   // 5
                        try {
                            myCloseable.close();   // 6
                        } catch (Throwable var11) {
                            var2.addSuppressed(var11);  // 7
                        }
                    } else {
                        myCloseable.close();
                    }
                }

            }
        } catch (Exception var14) {  // 9
            var14.printStackTrace(); 
            System.out.println("用户异常处理");
        }

    }
}

public class MyCloseable implements Closeable {
    @Override
    public void close() throws IOException {
        throw new RuntimeException("关闭资源异常"); 

    }
}

用户代码和关闭资源都有异常

  1. MyCloseable myCloseable = new MyCloseable(); 创建的时候也在用户异常捕获里面,所以不用担心new对象发生异常不处理
  2. 用户发生异常
  3. 准备抛出异常,但是发现有finally区,在抛出之前执行finally块的代码
  4. 执行finally代码区, 判断 myCloseable 为空 (当前不为空)
  5. 判断用户代码区是否有异常 (当前有异常)
  6. 关闭资源(else 代码块),发生异常,被最外层的用户异常所捕获
  7. 用户异常加上关闭资源的异常
  8. 真正抛出异常
  9. 执行用户异常处理

单资源关闭总结

所以这里做了非常充分异常处理.

做了了用户资源是否为空的处理,避免了: MyCloseable myCloseable = null; 时,去关闭资源.
不会

关闭多个资源的处理

如果想要关闭多个资源怎么办?

先关闭后面的还是先关闭前面的?

try (MyCloseable myCloseable = new MyCloseable();MyCloseable myCloseableA = new MyCloseable()) {
            System.out.println("完全没有异常");
} catch (Exception e) {
    e.printStackTrace();
    System.out.println("用户异常处理");
}

反编译内容


public class App {
    public App() {
    }

    public static void main(String[] args) {
        try {
            MyCloseable myCloseable = new MyCloseable();
            Throwable var2 = null;
            // 后面的 MyCloseable
            try {
                MyCloseable myCloseableA = new MyCloseable();
                Throwable var4 = null;

                try {
                    System.out.println("完全没有异常");
                } catch (Throwable var29) {
                    var4 = var29;
                    throw var29;
                } finally {
                    // 先处理后面的 myCloseableA
                    if (myCloseableA != null) {
                        if (var4 != null) {
                            try {
                                myCloseableA.close();
                            } catch (Throwable var28) {
                                var4.addSuppressed(var28);
                            }
                        } else {
                            myCloseableA.close();
                        }
                    }

                }
            } catch (Throwable var31) {
                var2 = var31;
                throw var31;
            } finally {
                // 后处理前面的 myCloseable
                if (myCloseable != null) {
                    if (var2 != null) {
                        try {
                            myCloseable.close();
                        } catch (Throwable var27) {
                            var2.addSuppressed(var27);
                        }
                    } else {
                        myCloseable.close();
                    }
                }

            }
        } catch (Exception var33) {
            var33.printStackTrace();
            System.out.println("用户异常处理");
        }

    }
}

这里和单资源关闭多了一点关于异常信息的内容:

用户异常 + 最后面的close异常 + 最前面的close异常信息。

多资源关闭总结

会先关闭后面的,在关闭前面的资源.

所以如果关闭多个资源时,对关闭顺序有要求的情况,一定不要写反了。

最后面的最先关闭,最前面的最后关闭

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: try-with-resourceJava SE7中引入的一个新特性,它可以简化资源管理的代码,同时也能够确保程序在完成资源使用后,能够正确地关闭资源。 在使用try-with-resource语句时,需要将要使用的资源对象放在try关键字的括号中。这个资源对象必须是实现了java.lang.AutoCloseable接口的类的对象。在try语句块执行完毕后,不需要手动关闭资源对象,try-with-resource语句自动调用资源对象的close()方法来关闭资源。这样可以避免忘记关闭资源或者错误地关闭资源所导致的问题。 下面是一个使用try-with-resource的例子,假设我们要读取一个文件的内容并打印出来: ``` try (BufferedReader reader = new BufferedReader(new FileReader("file.txt"))) { String line; while ((line = reader.readLine()) != null) { System.out.println(line); } } catch (IOException e) { // handle exception } ``` 在这个例子中,我们使用了try-with-resource语句来创建一个BufferedReader对象,并在try语句块中使用它来读取文件的内容。当try语句块执行完毕后,程序自动关闭BufferedReader对象。如果在读取文件的过程中发生了异常,程序也正确地处理异常并关闭资源。 ### 回答2: try-with-resource 语句是Java 7中引入的一种语法结构,用于在处理资源时自动关闭资源。在传统的Java代码中,我们使用try-catch-finally语句来处理资源的释放,但这种方式很容易导致遗漏关闭资源的情况。而try-with-resource语句则可以更简洁地处理这个问题。 try-with-resource语句的语法如下: ```java try (resource declaration) { // code that might throw an exception } catch (exception type) { // exception handling code } ``` 在try-with-resource语句中,我们可以在try关键字后面的括号中声明资源,这个资源必须是实现了AutoCloseable接口的类的实例。当try块执行完毕后,不论是正常执行还是发生异常,系统自动调用该资源的close()方法来关闭资源,无需显式编写关闭资源的代码。 这种语法的好处在于,无论代码是否抛出异常,资源都能正确关闭,避免了资源泄漏的问题。此外,由于资源关闭由系统自动处理,代码也更简洁清晰。 需要注意的是,try-with-resource语句中可以声明多个资源,多个资源之间使用分号分隔。资源的声明顺序决定了关闭顺序,即先声明的资源关闭。 总结而言,try-with-resource语句是一种在处理资源时自动关闭资源的语法结构。它不仅可以减少代码量,更重要的是能够确保资源的正确关闭,保证代码的健壮性和可靠性。 ### 回答3: try-with-resourceJava中的一种异常处理机制,用于自动关闭资源,确保资源正确关闭,同时减少了代码的冗余和异常处理的复杂性。 在Java 7中引入了try-with-resource语句,主要用于自动关闭实现了AutoCloseable接口的资源。使用try-with-resource语句能够简化资源关闭的代码,并且能够在try块执行完毕后自动关闭资源,不需要显式调用close方法。 try-with-resource语句的语法如下: try (资源初始化) { // 代码块 } catch (异常类型 异常对象) { // 异常处理 } finally { // 无需手动关闭资源 } 在try-with-resource语句中,资源的初始化在try关键字之后的括号中进行,可以同时初始化多个资源,多个资源之间使用分号分隔。 在执行try块里面的代码时,如果发生异常,首先执行catch块中的异常处理代码,当catch块执行完毕后,自动关闭初始化的资源,即使catch块中也发生了异常。而在try块里面如果没有发生异常,则直接执行finally块中的代码,并在执行完毕后自动关闭资源。 使用try-with-resource语句可以有效地处理资源关闭问题,避免资源泄漏和忘记手动关闭资源的情况发生。同时,由于try-with-resource语句能自动关闭资源,简化了代码的编写,更容易理解和维护。不过要注意,资源对象必须实现了AutoCloseable接口才能使用try-with-resource语句。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值