Effective Java -- 使用try-with-resources優化程式碼

達希_發表於2020-10-24

此係列文章為本人對《Effective Java》一書的學習筆記,主要是記錄對書中重點內容的理解。
既然有緣看到此文,那麼希望能對你有所幫助。
本文對應原書 第9條 try-with-resources優先於try-finally

引子

相信每一位Javaer都曾經在網上拷貝過程式碼,很多時候你拷的內容看起來相當的凌亂,你憂心忡忡,生怕沒法使用,但當你小心翼翼放入專案之中,卻驚喜的發現it works

激動之餘你自己研究起來,你發現程式碼裡使用到了很多的Stream,各種tryflushfinallyclose

在Java 7之前,你可能感嘆:“厲害啊,操作666”;
在Java 7以後,你應該嘆息:“又是一段被時代拋棄的程式碼”。

緣由

Java類庫中包括了很多呼叫close方法來手工關閉的資源,例如:

  • InputStream
  • OutputStream
  • java.sql.connection

相必不用我提大家也知道,若這些資源沒有進行正常的關閉,會造成怎樣的後果。
儘管這其中有很多的資源都是用終結方法作為安全網安全網可參考《Effective Java – 避免使用finalize方法》),但是終結方法本身的侷限性使得效果並不如人意

所以,在早期我們需要使用try-finally來關閉資源。如:

public static String readFirstLine() throws IOException {
	BufferedReader br = new BufferedReader(new FileReader("path"));
	try {
		return br.readLine(); // 語句1
	} finally {
		br.close(); // 語句2
	}
}

這樣看起來還湊合,但這畢竟只用了一個資源,如果資源數目增加,那麼程式碼就會越發臃腫。

另外,還有一個重要的原因,就是上述程式碼的語句1語句2,都有可能發生異常。

舉個例子:底層的物理裝置發生了異常,那麼readLine方法會丟擲異常,然後close方法也會發生異常,這下有趣的來了,第二個異常會把第一個異常“吃掉”(抹掉),在異常堆疊資訊中,你找不到有關第一個異常的記錄,這樣除錯會變得異常複雜。

救星

Java 7引入了try-with-resources語句,以上的問題迎刃而解。

所謂的try-with-resources,就是在try關鍵字後面加上一個括號,但要使用它,必須實現AutoClosable介面。
我們改造一下第一段程式碼:

public static String readFirstLine() throws IOException {
	try(BufferedReader br = new BufferedReader(new FileReader("path"))) {
		return br.readLine(); 
	} 
}

不僅僅變得簡潔,就連上述的異常被抹掉的情況也一併處理好了。這裡try-with-resources依然包含兩個語句,一個是readLine方法,還有一個是隱藏的close方法。

如果這兩個語句都出現了異常,那麼,後一個異常會被抑制(如果是多個異常,除了第一個,後續的都會被抑制)。

這樣做是為了保留你想看到的那個異常,而且這些被抑制的異常也並非被簡單的丟棄了,它們依然會被列印在堆疊軌跡中,並且註明它們是被抑制的,另外通過getSuppressed方法可以訪問的到(可以說是相當周到了)。

P.S. 中文版書中,對於英文原版的 “suppressed” 翻譯為“禁止”,個人認為不妥,所以採用了更為廣泛運用的“抑制”作為翻譯。

等等,這還沒完,try-with-resources還可以使用catch子句,這樣可以直接輕鬆的處理掉異常。我們繼續改造,不對異常進行丟擲,而是返回一個預設值:

public static String readFirstLine() {
	try(BufferedReader br = new BufferedReader(new FileReader("path"))) {
		return br.readLine(); 
	} catch (IOException e) {
		// 省略異常列印
		return DEFAULT_VALUE;
	}
}

總結

在使用必須關閉的資源時,我們要優先使用 try-with-resources,而不是 try-finally。前者的程式碼編寫簡單且更加簡潔有效,所以趕緊動手把你專案中的try-finally優化一下吧。

水平有限,若文章中存在錯誤,懇請不吝賜教,這對我以及後面的讀者都有重要意義

相關文章