在 Java SE 7 裡,還有另一個繼承 java.lang.AutoCloseable 的介面,所有 java.io package 裡的資料串流類別其實是實作這個介面,反而不是直接實作 java.lang.AutoCloseable 介面。這個介面就是 java.io.Closeable!
就兩個介面的宣告上來說,幾乎沒什麼差別,唯一的差別就是 java.io.Closeable 的 close 方法宣告會丟出 IOException 例外,而 java.lang.AutoCloseable 的 close 方法宣告會丟出 Exception 例外。當然每個資料串流類別實作 close 方法的細節不同,介面的好處就是,不管底層類別如何實作,介面的方法呼叫還是一樣。
我們再來設計一個實作 java.io.Closeable 介面的類別:
package idv.jacky.ironman4.day23;
import java.io.Closeable;import java.io.IOException;
public class MyResource2 implements Closeable{
public void close() throws IOException { System.out.println("Close resource 2."); }
}
MyResource2 類別跟昨天的 MyResource1 類別差不多,只差實作的介面不同。
有時因為程式的需要,我們可以在 try-with-resource 陳述式裡,宣告多個可關閉的物件嗎?答案當然是可以的,你就把 try-with-resource 的小括號當成一般的程式碼區塊,把要宣告的可關閉物件寫在裡面,每個物件的宣告用分號(;)隔開,例如:
package idv.jacky.ironman4.day23;
import idv.jacky.ironman4.day22.MyResource1;
public class Day23Example {
public static void main (String[] args) throws Exception {
try (MyResource1 r1 = new MyResource1();
MyResource2 r2 = new MyResource2()) {
System.out.println("Do something...");
}
}
}
現在要考考大家,這個範例程式會印出三個字串,請問順序會如何?毫無疑問的,"Do something…" 一定會是第一個,那接下來呢? MyResource1 和 MyResource2 哪個物件會先被關閉呢?規則是,後產生的物件會先被關閉,所以執行的結果會是:
為什麼會後宣告的先關閉呢?因為有可能你會在後宣告的物件裡,使用前面宣告的物件,例如:
package idv.jacky.ironman4.day23;
import java.io.BufferedReader;
import java.io.FileReader;
public class Day23Example2 {
public static void main(String[] args) throws Exception {
try (FileReader f = new FileReader("c:\\temp.txt");
BufferedReader b = new BufferedReader(f);) {
String line = b.readLine();
}
}
}
如果我們先關閉了第一個物件,有可能會讓第二個物件無法順利操作!所以在使用 tr-with-resource 陳述式時,請記得 後開先關 的原則!