新聞中心
這篇文章是我近期看了《Effective java》一書中總結(jié)的,來自其中第九條。為了對其理解的更加透徹,因此重新分析了一下,并加入了一些其他點。

我們注重客戶提出的每個要求,我們充分考慮每一個細(xì)節(jié),我們積極的做好成都網(wǎng)站制作、網(wǎng)站建設(shè)、外貿(mào)網(wǎng)站建設(shè)服務(wù),我們努力開拓更好的視野,通過不懈的努力,創(chuàng)新互聯(lián)公司贏得了業(yè)內(nèi)的良好聲譽,這一切,也不斷的激勵著我們更好的服務(wù)客戶。 主要業(yè)務(wù):網(wǎng)站建設(shè),網(wǎng)站制作,網(wǎng)站設(shè)計,成都小程序開發(fā),網(wǎng)站開發(fā),技術(shù)開發(fā)實力,DIV+CSS,PHP及ASP,ASP.Net,SQL數(shù)據(jù)庫的技術(shù)開發(fā)工程師。
“ 本文的所有例子均在本地代碼運行完畢
基于JDK版本1.8,運行環(huán)境eclipse
本文類名:TryWithResources,下文的堆棧信息也以此為基礎(chǔ) ”
在java開發(fā)中,一些網(wǎng)絡(luò)鏈接或者是文件資源都需要程序員去手動調(diào)用close方法關(guān)閉,比如InputStream、OutputStream和java.sql.Connection。如果忘關(guān)了就可能造成嚴(yán)重的性能后果。而關(guān)閉的方法有很多種。比如finalizer、try-catch-finally、try-with-resources等等。
finalizer機制可以關(guān)閉,但是其執(zhí)行性不可預(yù)測,還有可能造成內(nèi)存泄漏,所以一般不使用,雖然java9還提出了cleaner機制代替了finalizer機制,但是其執(zhí)行依然不可預(yù)測,因此選擇就落在了try-catch-finally和try-with-resources之間。
本文就是為了討論該選擇哪一種比較好,不過題目已經(jīng)給出了答案肯定是try-with-resources。下面帶著這個答案去分析為什么推薦使用try-with-resources而不是try-finally。
一、前言
在正式分析之前,我們先看一波finally的執(zhí)行順序。
1、finally不是必要條件
也就是說try-catch-finally中,可以只有try-catch,也可以只有try-finally。
2、假設(shè)基于try-catch-finally:
第一:代碼沒有異常
執(zhí)行順序:try執(zhí)行完整->catch不執(zhí)行->finally執(zhí)行
第二:代碼有異常且catch進行捕獲
執(zhí)行順序:try執(zhí)行部分->跳轉(zhuǎn)catch捕獲處理->finally執(zhí)行
第三:代碼有異常且catch不捕獲:這種情況沒有catch
執(zhí)行順序:try執(zhí)行部分->finally執(zhí)行
從上面的執(zhí)行順序可以看出,finally語句不管在哪種情況是一定會執(zhí)行的?;谶@個認(rèn)識,現(xiàn)在我們再來分析。
二、try-finally的缺點
先看案例,本案例來自《Effective java》,現(xiàn)在要關(guān)閉資源:
- static String firstLineOfFile(String path) throws IOException {
- BufferedReader reader = new BufferedReader(new FileReader(path));
- try {
- return reader.readLine();
- } finally {
- reader.close();
- }
- }
關(guān)閉一個資源還好,但是如果再添加第二個資源,代碼看起來就會一團糟了。
- static void copy(String src, String desc) throws IOException {
- InputStream in = new FileInputStream(src);
- try {
- OutputStream out = new FileOutputStream(desc);
- byte[] bytes = new byte[1024];
- int n;
- try {
- while ((n = in.read(bytes)) != -1) {
- out.write(bytes, 0, n);
- }
- } finally {
- out.close();
- }
- } finally {
- in.close();
- }
- }
如果需要關(guān)閉的資源不僅種類多,而且數(shù)量也很多。那代碼可就太龐大了。現(xiàn)在對這種方式的缺點進行一波總結(jié):
1. 關(guān)閉的資源多事,代碼復(fù)雜
2. 對于第一個案例,如果設(shè)備出現(xiàn)異常,那么那么調(diào)用readLine就會拋出異常,同時close方法也出現(xiàn)異常,在這種情況下,close異常會完全抹去readLine異常。在異常堆棧軌跡中也完全沒有readLine異常的記錄。
現(xiàn)在來測試一邊:
基于以上原因,出現(xiàn)了try-with-resources。
三、try-with-resources的優(yōu)勢
try-with-resources是在jdk1.7引入的,可以完美解決以上的問題。要使用這個構(gòu)造的資源,必須先實現(xiàn)AutoCloseable接口,其中包含了單個返回void的close方法,Java類庫與第三方類庫中的許多類和接口,現(xiàn)在都實現(xiàn)或擴展了AutoCloseable接口,因此我們現(xiàn)在不必實現(xiàn)了。
既然try-with-resources能夠解決以上的問題,現(xiàn)在來看一下,如何解決的:
1、代碼復(fù)雜問題解決
- static void copy(String src, String desc) throws IOException {
- try (InputStream in = new FileInputStream(src);
- OutputStream out = new FileOutputStream(desc)) {
- byte[] bytes = new byte[1024];
- int n;
- while ((n = in.read(bytes)) != -1) {
- out.write(bytes, 0, n);
- }
- }
- }
可以看出這種方式代碼更加簡單,出現(xiàn)了錯誤,也能快速定位。
2、異常抹去問題解決
- static String firstLineOfFil (String path) throws IOException {
- try (BufferedReader reader = new BufferedReader(new FileReader(path))) {
- return reader.readLine();
- }
- }
如果readLine和不可見的close方法都拋出異常,close方法拋出的異常就會被禁止,try-finally處理機制中我們無法看到,堆棧軌跡中也不能打印,但是try-with-resources不一樣,全部會被打印在堆棧軌跡中,并注明它們是被禁止的異常,通過編寫調(diào)用getSuppressed方法還可以訪問到它們?,F(xiàn)在再來測試一遍。
OK,上面基本上全部分析完畢,但是此書還給出了一個更好的案例:
- static String firstLineOfFile(String path, String defaultVal) {
- try (BufferedReader reader = new BufferedReader(new FileReader(path))) {
- return reader.readLine();
- } catch (IOException e) {
- return defaultVal;
- }
- }
這個firstLineOfFile方法沒有拋出異常,但是如果它無法打開文件,或者無法從中讀取,就會返回一個默認(rèn)值。
結(jié)論
處理必須關(guān)閉的資源時,始終要優(yōu)先考慮使用try-with-resources,而不是try-finally。這樣得到的代碼將更簡潔,清晰,產(chǎn)生的異常也更有價值,這些也是try-finally無法做到的。
網(wǎng)頁名稱:為什么不推薦使用try-catch-finally處理Java異常?
文章位置:http://m.fisionsoft.com.cn/article/djohpjd.html


咨詢
建站咨詢
