java.lang.AutoCloseable


JDK7的嘗試關閉資源語法可套用的物件,必須實作java.lang.AutoCloseable介面,這可以在API文件上得知:

Scanner實作了AutoCloseable


AutoCloseable是JDK7新增的介面,僅定義了close()方法:

package java.lang;
public interface AutoCloseable {
    void close() throws Exception;
}

所有繼承AutoCloseable的子介面,或實作AutoCloseable的類別,可在AutoCloseable的API文件上查詢得知:

AutoCloseable的子介面與實作類別


只要實作AutoCloseable介面,就可以套用至嘗試關閉資源語法,以下是個簡單示範:

package cc.openhome;

public class Main {    
    public static void main(String[] args) {
        try(Resource res = new Resource()) {
            res.doSome();
        } catch(Exception ex) {
            ex.printStackTrace();
        }
    }
}

class Resource implements AutoCloseable {
    void doSome() {
        System.out.println("作一些事");
    }
    @Override
    public void close() throws Exception {
        System.out.println("資源被關閉");
    }
}

執行結果如下:

作一些事
資源被關閉

嘗試關閉資源語法也可以同時關閉兩個以上的物件資源,只要中間以分號區隔。來看看以下的範例,哪個物件資源會先被關閉呢?

package cc.openhome;

public class Main2 {    
    public static void main(String[] args) {
        try(ResourceSome some = new ResourceSome();
             ResourceOther other = new ResourceOther()) {
            some.doSome();
            other.doOther();
        } catch(Exception ex) {
            ex.printStackTrace();
        }
    }
}

class ResourceSome implements AutoCloseable {
    void doSome() {
        System.out.println("作一些事");
    }
    @Override
    public void close() throws Exception {
        System.out.println("資源Some被關閉");
    }
}

class ResourceOther implements AutoCloseable {
    void doOther() {
        System.out.println("作其它事");
    }
    @Override
    public void close() throws Exception {
        System.out.println("資源Other被關閉");
    }
}

try的括號中,越後面撰寫的物件資源會越早被關閉。執行結果如下,ResourceOther實例會先被關閉,然後再關閉ResourceSome實例:

作一些事
作其它事
資源Other被關閉
資源Some被關閉

可以實際觀察反組譯之後的程式碼,會發現每個AutoCloseable物件,都獨立使用一個trycatchfinallytry括號中越後面撰寫的物件,會是在越內層的trycatchfinally中:

...
try {
    ResourceSome some = new ResourceSome();
    Throwable localThrowable3 = null;
    try {
        ResourceOther other = new ResourceOther();
        Throwable localThrowable4 = null;
        try {
            some.doSome();
            other.doOther();
        } catch (Throwable localThrowable1) {
            localThrowable4 = localThrowable1;
            throw localThrowable1;
        } finally {  // 處理ResourceOther的關閉
            if (localThrowable4 != null) {
                try {
                    other.close();
                } catch (Throwable x2) {
                    localThrowable4.addSuppressed(x2);
                 }
            } else {
                other.close();
            }
        }
    } catch (Throwable localThrowable2) {
        localThrowable3 = localThrowable2;
        throw localThrowable2;
    } finally {  // 處理ResourceSome的關閉
        if (localThrowable3 != null) {
            try {
                some.close();
            } catch (Throwable x2) {
                localThrowable3.addSuppressed(x2);
            }
        } else {
            some.close();
        }
    }
} catch (Exception ex) {
    ex.printStackTrace();
}