老實說,要抓還是要拋? 撰寫的FileUtil範例並不是很正確,之後在學習輸入輸出時會談到,如果建構FileInputStream實例就會開啟檔案,不使用時,應該呼叫close()關閉檔案。FileUtil中是透過Scanner搭配FileInputStream來讀取檔案,實際上Scanner物件有個close()方法,可以關閉Scanner相關資源與搭配的FileInputStream。
那麼要何時關閉資源呢?如下撰寫並不是很正確:
...
public static String readFile(String name) throws FileNotFoundException {
StringBuilder builder = new StringBuilder();
Scanner scanner = new Scanner(new FileInputStream(name));
while (scanner.hasNext()) {
builder.append(scanner.nextLine());
builder.append('\n');
}
scanner.close();
return builder.toString();
}
...
如果scanner.close()前發生了任何例外,執行流程就會中斷,因此scanner.close()就可能不會執行,因此Scanner及搭配的FileInputStream就不會被關閉。
你想要的是無論如何,最後一定要執行關閉資源的動作,try、catch語法還可以搭配finally,無論try區塊中有無發生例外,若撰寫有finally區塊,則finally區塊一定會被執行。例如:
package cc.openhome;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.Scanner;
public class FileUtil {
public static String readFile(String name) throws FileNotFoundException {
StringBuilder builder = new StringBuilder();
Scanner scanner = null;
try {
scanner = new Scanner(new FileInputStream(name));
while (scanner.hasNext()) {
builder.append(scanner.nextLine());
builder.append('\n');
}
} finally {
if(scanner != null) {
scanner.close();
}
}
return builder.toString();
}
}
由於finally區塊一定會被執行,這個範例中scanner原先是null,若FileInputStream建構失敗,則scanner就有可能還是null,因此在finally區塊中必須先檢查scanner是否有參考物件,有的話才進一步呼叫close()方法,否則scanner參考至null又打算呼叫close()方法,反而會拋出NullPointerException。
如果程式撰寫的流程中先return了,而且也有寫finally區塊,那finally區塊會先執行完後,再將值傳回。例如,下面這個範例會先顯示「finally...」再顯示「1」:
package cc.openhome;
public class Main {
public static void main(String[] args) {
System.out.println(test(true));
}
static int test(boolean flag) {
try {
if(flag) {
return 1;
}
} finally {
System.out.println("finally...");
}
return 0;
}
}

