老實說,要抓還是要拋? 撰寫的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;
}
}