阿男的小窝

View the Project on GitHub

在Java 8里面引入了「Autoclosable」接口,关于这个接口和「try-with-resources clause」的详细用法,可以查看这篇文档1,本文简单记录它的使用方法。

public class FooClass implements AutoCloseable {
    @Override
    public void close() throws Exception {
        System.out.println("close() method called");
    }
}
public class PlayWithAutoclosable  {
    public static void main(String[] args) {
        try (FooClass foo = new FooClass()) {
            // use the FooClass instance here.
            System.out.println(foo);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

如上代码所示,我们创建了一个「FooClass」,它实现了「AutoCloseable」接口,这个接口定义一个「close()」方法,会在「try-with-resources clause」执行结束后被自动调用,等于代替了原有的「finally clause」。

第二个「PlayWithAutoclosable」展示了如何在「try-with-resources clause」里面使用第一个「FooClass」。执行这个class的main方法,结果如下:

lang.PlayWithAutoclosable$FooClass@4769b07b
close() method called

可以看到「close()」方法在「try-with-resources clause」执行完毕之后被自动执行了。

如果把编译后的「PlayWithAutoclosable」给解码成bytecodes,可以看到多处执行「close()」的calls:

$ javap -c ./target/classes/lang/autoclosable/PlayWithAutoclosable.class
Compiled from "PlayWithAutoclosable.java"
public class lang.autoclosable.PlayWithAutoclosable {
  public lang.autoclosable.PlayWithAutoclosable();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: new           #2                  // class lang/autoclosable/FooClass
       3: dup
       4: invokespecial #3                  // Method lang/autoclosable/FooClass."<init>":()V
       7: astore_1
       8: aconst_null
       9: astore_2
      10: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;
      13: aload_1
      14: invokevirtual #5                  // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
      17: aload_1
      18: ifnull        88
      21: aload_2
      22: ifnull        41
      25: aload_1
      26: invokevirtual #6                  // Method lang/autoclosable/FooClass.close:()V
      29: goto          88
      32: astore_3
      33: aload_2
      34: aload_3
      35: invokevirtual #8                  // Method java/lang/Throwable.addSuppressed:(Ljava/lang/Throwable;)V
      38: goto          88
      41: aload_1
      42: invokevirtual #6                  // Method lang/autoclosable/FooClass.close:()V
      45: goto          88
      48: astore_3
      49: aload_3
      50: astore_2
      51: aload_3
      52: athrow
      53: astore        4
      55: aload_1
      56: ifnull        85
      59: aload_2
      60: ifnull        81
      63: aload_1
      64: invokevirtual #6                  // Method lang/autoclosable/FooClass.close:()V
      67: goto          85
      70: astore        5
      72: aload_2
      73: aload         5
      75: invokevirtual #8                  // Method java/lang/Throwable.addSuppressed:(Ljava/lang/Throwable;)V
      78: goto          85
      81: aload_1
      82: invokevirtual #6                  // Method lang/autoclosable/FooClass.close:()V
      85: aload         4
      87: athrow
      88: goto          96
      91: astore_1
      92: aload_1
      93: invokevirtual #10                 // Method java/lang/Exception.printStackTrace:()V
      96: return
    Exception table:
       from    to  target type
          25    29    32   Class java/lang/Throwable
          10    17    48   Class java/lang/Throwable
          10    17    53   any
          63    67    70   Class java/lang/Throwable
          48    55    53   any
           0    88    91   Class java/lang/Exception
}

如上所示,编译后的代码在多处都有「FooClass.close()」的痕迹,其实就是保证在多处Throwable和Exception发生后,最终都会call到「close()」方法,实际上就是「finally」的作用。

  1. https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html