Effective Java -- 使用try-with-resources優化程式碼
此係列文章為本人對《Effective Java》一書的學習筆記,主要是記錄對書中重點內容的理解。
既然有緣看到此文,那麼希望能對你有所幫助。
本文對應原書第9條 try-with-resources優先於try-finally
引子
相信每一位Javaer都曾經在網上拷貝過程式碼,很多時候你拷的內容看起來相當的凌亂,你憂心忡忡,生怕沒法使用,但當你小心翼翼放入專案之中,卻驚喜的發現it works。
激動之餘你自己研究起來,你發現程式碼裡使用到了很多的Stream
,各種try
、flush
、finally
、close
。
在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
優化一下吧。
水平有限,若文章中存在錯誤,懇請不吝賜教,這對我以及後面的讀者都有重要意義
相關文章
- Java學習之程式碼優化Java優化
- 使用Web Worker優化程式碼Web優化
- Java程式碼編寫、程式碼優化技巧總結Java優化
- Java 7 Try-With-ResourcesJava
- 從try-with-resources到ThreadLocal,最佳化你的程式碼編寫方式!thread
- [譯]Effective Kotlin系列之使用Sequence來優化集合的操作(四)Kotlin優化
- java程式碼編寫優化(持續更新...)Java優化
- 使用 IoC 容器進行程式碼優化行程優化
- 程式碼優化優化
- javaScript程式碼優化JavaScript優化
- 優化If else(簡化程式碼)優化
- Java優化if-else程式碼幾個解決方案Java優化
- Android Note - 程式碼優化Android優化
- Java效能優化:教你提高程式碼執行的效率Java優化
- Effective Java 避免使用終結方法和清空方法Java
- 在 .NET 平臺使用 ReflectionDynamicObject 優化反射呼叫程式碼Object優化反射
- Java 高效程式設計(Effective Java)中文第三版Java程式設計
- [譯]Effective Kotlin系列之考慮使用原始型別的陣列優化效能(五)Kotlin型別陣列優化
- 深入理解Java虛擬機器(程式編譯與程式碼優化)Java虛擬機編譯優化
- effective java 觀後感Java
- 《Effective Java》--Java進階必備Java
- 你見過哪些優雅的 Java 程式碼最佳化技巧?Java
- 如何提高Java程式碼質量-優雅的寫程式碼Java
- 優化程式碼中的“壞味道”優化
- Python 程式碼的效能優化之道Python優化
- 前端程式碼質量優化交流前端優化
- 前端效能優化—js程式碼打包前端優化JS
- PHP 程式碼優化技巧總結PHP優化
- PostgreSQL 優化器程式碼概覽SQL優化
- 【程式碼優化】List.remove() 剖析優化REM
- 祖傳程式碼如何優化效能?優化
- 淺談JavaScript程式碼效能優化JavaScript優化
- 如何優化 Vue 祖傳程式碼優化Vue
- 記一次使用策略模式優化程式碼的經歷模式優化
- 使用pegjs解析java程式碼JSJava
- 使用java程式碼操作redisJavaRedis
- Java程式碼工具EasyCode使用Java
- Java語法糖: 使用 try-with-resources 語句安全地釋放資源Java