美文网首页
'try(A a = new A())' VS 'try fin

'try(A a = new A())' VS 'try fin

作者: 明年我18 | 来源:发表于2019-11-22 09:54 被阅读0次

    实现了AutoCloseable接口的类,可以在try的时候直接实例化对象。try代码块完成之后,自动调用close方法,相当于在finally里主动调用。但是出现异常后的流程和try finally有什么不同呢? 下面写代码测试一下。

    首先定义一个类Cat,实现AutoCloseable接口

    class Cat implements AutoCloseable{
        void sayHello() throws Exception {
            Utils.println("calling sayHello(), I will throw an exception");
            throw new Exception("Exception in sayHello() ");
        }
    
        @Override
        public void close() throws Exception {
            Utils.println("I'm closing, I will throw an exception");
            throw new Exception("Exception in close()");
        }
    }
    

    我们的这个Cat有以下特点:

    • sayHello方法会抛出异常
    • close方法也会抛出异常

    test v1: 'try(Cat cat = new Cat())' VS 'try finally'

    没有catch(不要被外层的catch迷惑,那只是为了打印异常)

    static void testV1(){
        Utils.println("----try(Cat cat = new Cat())-----");
        try{
            try(Cat cat = new Cat()){
                cat.sayHello();
            }
    
        }catch (Exception e){
            Utils.println("cache error in main (" + e + "), let's see its stack trace");
            Utils.printStackTrace(e);
        }
        Utils.println("--------------");
    
        Utils.println("----try finally-----");
        try{
            Cat cat = null;
            try{
                cat = new Cat();
                cat.sayHello();
            }finally {
                if(cat != null){
                    cat.close();
                }
            }
        }catch (Exception e){
            Utils.println("cache error in main (" + e + "), let's see its stack trace");
            Utils.printStackTrace(e);
        }
        Utils.println("--------------");
    }
    

    结果输出:

    ----test v1----------------------------------------
    ----try(Cat cat = new Cat())-----
    calling sayHello(), I will throw an exception
    I'm closing, I will throw an exception
    cache error in main (java.lang.Exception: Exception in sayHello() ), let's see its stack trace
    java.lang.Exception: Exception in sayHello() 
        at Cat.sayHello(Cat.java:4)
        at Test.testV1(Test.java:16)
        at Test.main(Test.java:4)
        Suppressed: java.lang.Exception: Exception in close()
            at Cat.close(Cat.java:10)
            at Test.testV1(Test.java:17)
            ... 1 more
    --------------
    ----try finally-----
    calling sayHello(), I will throw an exception
    I'm closing, I will throw an exception
    cache error in main (java.lang.Exception: Exception in close()), let's see its stack trace
    java.lang.Exception: Exception in close()
        at Cat.close(Cat.java:10)
        at Test.testV1(Test.java:33)
        at Test.main(Test.java:4)
    --------------
    

    结论

    • try(Cat cat = new Cat())
      • try代码块完成之后会自动调用close
      • close抛出的异常,被Suppressed了,外层捕获的只有sayHello的异常,但通过堆栈可以找到这个Suppressed的异常
    • try finally
      • 外层捕获的是在finally执行close时抛出的异常,sayHello的异常完全不见了。

    test v2: 'try(Cat cat = new Cat()) catch{}' VS 'try catch finally'

    有catch,并且catch里再抛出异常

    static void testV2(){
        Utils.println("----try(Cat cat = new Cat()) catch-----");
        try{
            try(Cat cat = new Cat()){
                cat.sayHello();
            } catch (Exception e) {
                Utils.println("cached err (" + e.getMessage() + "), I will throw an exception again");
                throw new Exception("Exception in catch", e);
            }
    
        }catch (Exception e){
            Utils.println("cache error in main (" + e + "), let's see its stack trace");
            Utils.printStackTrace(e);
        }
        Utils.println("-----------------------------------------");
    
        Utils.println("----try catch finally--------------------");
        try{
            Cat cat = null;
            try{
                cat = new Cat();
                cat.sayHello();
            } catch (Exception e) {
                Utils.println("cached err (" + e.getMessage() + "), I will throw an exception again");
                throw new Exception("Exception in catch", e);
            }finally {
                if(cat != null){
                    cat.close();
                }
            }
        }catch (Exception e){
            Utils.println("cache error in main (" + e + "), let's see its stack trace");
            Utils.printStackTrace(e);
        }
        Utils.println("-------------------------------------------");
    }
    

    结果输出

    ----test v2------
    ----try(Cat cat = new Cat()){} catch{}-----
    calling sayHello(), I will throw an exception
    I'm closing, I will throw an exception
    cached err (Exception in sayHello() ), I will throw an exception again
    cache error in main (java.lang.Exception: Exception in catch), let's see its stack trace
    java.lang.Exception: Exception in catch
        at Test.testV2(Test.java:50)
        at Test.main(Test.java:8)
    -----------------------------------------
    ----try catch finally--------------------
    calling sayHello(), I will throw an exception
    cached err (Exception in sayHello() ), I will throw an exception again
    I'm closing, I will throw an exception
    cache error in main (java.lang.Exception: Exception in close()), let's see its stack trace
    java.lang.Exception: Exception in close()
        at Cat.close(Cat.java:10)
        at Test.testV2(Test.java:70)
        at Test.main(Test.java:8)
    -------------------------------------------
    ---------------------------------------------------------------------
    

    结论

    • try(Cat cat = new Cat()) catch
      • catch之前就调用了close(符合try代码块完成之后会自动调用close这个结论)
      • catch到的是sayHello的异常,close抛出的异常依然被Suppressed了
      • catch中再次抛出的异常被外层捕获
    • try catch finally
      • 先走catch,再走finally,所以catch捕获的是sayHello的异常
      • catch中再次抛出的异常不见了,外层捕获的是在finally执行close时抛出的异常。

    测试代码地址:https://github.com/kongxiangxin/pine/tree/master/auto-closeable

    相关文章

      网友评论

          本文标题:'try(A a = new A())' VS 'try fin

          本文链接:https://www.haomeiwen.com/subject/qdjfwctx.html