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

Keywords: Java github

Classes that implement the AutoCloseable interface can instantiate objects directly when trying.When the try block is complete, the close method is called automatically, which is equivalent to calling it actively in finally.But what is the difference between the process after an exception and try finally?Write a code test below.

First define a class Cat to implement the AutoCloseable interface

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()");
    }
}

Our Cat has the following features:

  • The sayHello method throws an exception
  • The close method also throws an exception

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

No catch (don't get confused by the outer catch, it's just for printing exceptions)

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("--------------");
}

Output of results:

----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)
--------------

conclusion

  • try(Cat cat = new Cat())
    • close is called automatically when the try block is complete
    • close throws an exception, which is Suppresseded. The outer layer only catches the exception of sayHello, but this Suppresseded exception can be found on the stack
  • try finally
    • The outer layer captures the exception thrown when finally close s, and the sayHello exception is completely missing.

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

There is a catch and an exception is thrown in the 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("-------------------------------------------");
}

Output of Results

----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)
-------------------------------------------
---------------------------------------------------------------------

conclusion

  • try(Cat cat = new Cat()) catch
    • Close was called before catch (the conclusion that close is automatically called after a try-compliant block is completed)
    • catch gets an exception for sayHello, and close throws an exception that is still Suppressed ed
    • An exception thrown again in the catch is caught by the outer layer
  • try catch finally
    • Catch first, then finally, so catch catches the exception of sayHello
    • The exception thrown again in the catch disappears, and the outer layer captures the exception thrown when finally close s.

Test code address: https://github.com/kongxiangxin/pine/tree/master/auto-closeable

Posted by dcampbell18 on Thu, 21 Nov 2019 19:05:31 -0800