為什麼推薦使用try-with-resources代替try-finally

2020-12-22 愚公要移山1

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

本文的所有例子均在本地代碼運行完畢基於JDK版本1.8,運行環境eclipse本文類名:TryWithResources,下文的堆棧信息也以此為基礎

在java開發中,一些網絡連結或者是文件資源都需要程式設計師去手動調用close方法關閉,比如InputStream、OutputStream和java.sql.Connection。如果忘關了就可能造成嚴重的性能後果。而關閉的方法有很多種。比如finalizer、try-catch-finally、try-with-resources等等。

finalizer機制可以關閉,但是其執行性不可預測,還有可能造成內存洩漏,所以一般不使用,雖然java9還提出了cleaner機制代替了finalizer機制,但是其執行依然不可預測,因此選擇就落在了try-catch-finally和try-with-resources之間。

本文就是為了討論該選擇哪一種比較好,不過題目已經給出了答案肯定是try-with-resources。下面帶著這個答案去分析為什麼推薦使用try-with-resources而不是try-finally。

一、前言

在正式分析之前,我們先看一波finally的執行順序。

1、finally不是必要條件

也就是說try-catch-finally中,可以只有try-catch,也可以只有try-finally。

2、假設基於try-catch-finally:

第一:代碼沒有異常

執行順序:try執行完整->catch不執行->finally執行

第二:代碼有異常且catch進行捕獲**

執行順序:try執行部分->跳轉catch捕獲處理->finally執行

第三:代碼有異常且catch不捕獲:這種情況沒有catch**

執行順序:try執行部分->finally執行

從上面的執行順序可以看出,finally語句不管在哪種情況是一定會執行的。基於這個認識,現在我們再來分析。

二、try-finally的缺點

先看案例,本案例來自《Effective java》,現在要關閉資源:

static String firstLineOfFile(String path)throws IOException {BufferedReader reader = new BufferedReader(new FileReader(path));try {return reader.readLine(); } finally { reader.close(); }}

關閉一個資源還好,但是如果再添加第二個資源,代碼看起來就會一團糟了。

staticvoidcopy(String src, String desc)throws IOException {InputStream in = new FileInputStream(src);try { OutputStream out = new FileOutputStream(desc);byte[] bytes = newbyte[1024];int n;try {while ((n = in.read(bytes)) != -1) { out.write(bytes, 0, n); } } finally { out.close(); } } finally { in.close(); }}

如果需要關閉的資源不僅種類多,而且數量也很多。那代碼可就太龐大了。現在對這種方式的缺點進行一波總結:

1. 關閉的資源多事,代碼複雜

2. 對於第一個案例,如果設備出現異常,那麼那麼調用readLine就會拋出異常,同時close方法也出現異常,在這種情況下,close異常會完全抹去readLine異常。在異常堆棧軌跡中也完全沒有readLine異常的記錄。

現在來測試一邊:

基於以上原因,出現了try-with-resources。

三、try-with-resources的優勢

try-with-resources是在jdk1.7引入的,可以完美解決以上的問題。要使用這個構造的資源,必須先實現AutoCloseable接口,其中包含了單個返回void的close方法,Java類庫與第三方類庫中的許多類和接口,現在都實現或擴展了AutoCloseable接口,因此我們現在不必實現了。

既然try-with-resources能夠解決以上的問題,現在來看一下,如何解決的:

1、代碼複雜問題解決

staticvoidcopy(String src, String desc)throws IOException {try (InputStream in = new FileInputStream(src);OutputStream out = new FileOutputStream(desc)) {byte[] bytes = newbyte[1024];int n;while ((n = in.read(bytes)) != -1) { out.write(bytes, 0, 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不一樣,全部會被列印在堆棧軌跡中,並註明它們是被禁止的異常,通過編寫調用getSuppressed方法還可以訪問到它們。現在再來測試一遍。

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方法沒有拋出異常,但是如果它無法打開文件,或者無法從中讀取,就會返回一個默認值。

結論

處理必須關閉的資源時,始終要優先考慮使用try-with-resources,而不是try-finally。這樣得到的代碼將更簡潔,清晰,產生的異常也更有價值,這些也是try-finally無法做到的。

相關焦點

  • 面試官:當return遇到try、catch、finally時會發生什麼?
    當try中帶有return時,會先執行return前的代碼,然後暫時保存需要return的信息,再執行finally中的代碼,最後再通過return返回之前保存的信息。所以,這裡方法返回的值是try中計算後的2,而非finally中計算後的10。當finally中帶有return的時候又會出現什麼結果呢?
  • 聽歌學英文| Try
    , try, try, try你不必去試著努力You don't have to try, try, try, try你不必去試著努力You don't have to try, try, try, try
  • 音樂 Colbie Caillat - Try
    為什麼總要錯過之後,才發現那些失落的美好?要知道,我們生命中的每一天,都是人生中最年輕的一天。為什麼必須要他人提醒,你才能看見自己的優點?要知道,我們是彼此的鏡子,如果你能從他人身上發現美,那麼,你也一樣。如果你總是看不見自己的美,那該有多遺憾……卸掉妝容,去愛最真實的自己!
  • 歌曲分享| Try --Colbie Caillat
    a single thing  你不必做出任何改變  You don't have to try, try, try, try  你不必去試著努力  You don't have to try, try, try, try  你不必去試著努力  You don't have to try, try, try, try  你不必去試著努力
  • Colbie Caillat(蔻比·凱蕾)《Try》
    have to change a single thing你不必逼自己做任何改變You don't have to try, try, try, try你不必試著,試著努力You don't have to try, try, try, try你不必試著,試著努力You don't have to try, try,
  • Why Try to Change Me now
    所以我漫步雨中I've got some habits我有一些奇怪的習慣Even I can't explain即使我自己也無法解釋Could start for the corner本來只是想要去偏僻的地方Turn up in Spain卻發現自己來到了西班牙Why try
  • Trytry與美圖美妝和滙豐銀行實現三方合作
    trytry集團、美圖美妝與滙豐銀行達成戰略合作共識,三方將在供應鏈金融、新零售、大數據應用、電子商務等業務領域開展戰略合作,合作中,三方將通過大數據風控,整合上下遊產業鏈資源,實現金融為實體服務。trytry作為美圖美妝APP的全面管理者,trytry集團聯合創始人兼trytry及美圖美妝合伙人、新零售總經理歐澤超表示:「此次與滙豐銀行達成戰略合作共識,將為廣大用戶提供更便捷、安全的金融服務。」
  • 「good try」是什麼意思?
    good try:很好的嘗試;不錯。Good try, but do you really think I would believe that?厲害厲害,但你真的認為我會相信嗎?So this paper makes a good try.本文做了一個很好的嘗試。It was a good try but it didn't succeed.這是一個很好的嘗試,但沒有成功。
  • 最勵志的兩首Try
    have to change a single thing你不必逼自己做任何改變You don't have to try, try, try, try你不必試著,試著努力You don't have to try, try, try, try你不必試著,試著努力You don't have to try, try,
  • Try—Colbie Caillat吉他譜
    >                  FYou don't have to try, try, try, try                  CYou don't have to try, try, try, try                  G (strum once)You don't have to try
  • Try(附歌詞解析)
    to change a single thing你不必逼自己做任何改變You don't have to try, try, try, try你不必試著去努力嘗試You don't have to try, try, try, try你不必試著去努力嘗試You don't have to try, try, try
  • 超好聽的英文歌《Try》
    to chase your dream當你努力狂奔,追逐你的夢想It's time for us to make a move cause we are asking one another to change是時候邁出腳步為彼此而改變了And maybe I'm not ready或許我沒準備好But I'll try
  • try和do one's best的區別
    The difference between "try" or "do one's best" - Alan, China 我想知道try和do one's best之間的區別。我的英語老師告訴我它們是一樣的。但我相信每個詞都有區別。你能幫助我嗎?
  • 【音樂】Colbie Caillat 火爆單曲《Try》
    跟他們一樣,他們才會喜歡你You don't have to try so hard你喜歡你自己嗎?, try, try, try你不必勉強You don't have to try你不必勉強Get your shopping on, at the mall去商場盡情購物max your credit cards把信用卡刷爆You don't have to choose, buy it
  • Colbie Caillat《Try》---【S.T.C Music】
    跟他們一樣,他們才會喜歡你You don't have to try so hard你喜歡你自己嗎?你不必如此勉強give it all away你不必放棄真我You just have to get up, get up, get up, get up你只需勇敢面對自己You don't have to change a single thing你無需做出任何改變You don't have to try
  • python編程從入門到實踐:使用try-except代碼塊
    try:number1=int(input("請輸入一個數字:"))number2=int(input("請輸入一個數字:"))print(number1+number2)except ValueError
  • 不用try catch,如何機智的捕獲錯誤
    (給前端大全加星標,提升前端技能)作者: 魔術師卡頌 公號 / 卡頌 (本文來自作者投稿)這是多個feature組合使用後實現的神奇效果
  • 領導說:try-catch要放在循環體外!
    很多人對 try-catch 有一定的誤解,比如我們經常會把它(try-catch)和「低性能」直接畫上等號,但對 try-catch 的本質(是什麼)卻缺少著最基礎的了解,因此我們也會在本篇中對 try-catch 的本質進行相關的探索。
  • I will try並不是我盡力試試!外國人是這樣理解的!
    我們都知道try是嘗試,當我們想表達"我會盡力去做",經常會說I will try或I will try my best.但這樣的英文,在外國人聽來,很多時候,並不是你想的這個意思。到底是什麼,我們來看!1、I will try該怎麼翻譯?
  • ...Please wait a few minutes and try again.是什麼意思 中文...
    Please wait a few minutes and try again.是什麼意思?許多玩家不太清楚這個英文的意思,下面就讓... lol手遊We've received your request.