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

2020-12-26 愚公要移山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無法做到的。

相關焦點

  • Try..Catch 不能捕獲的錯誤有哪些?注意事項又有哪些?
    今天的內容中,我們來學習一下使用try、catch、finally和throw進行錯誤處理。我們還會講一下 JS 中內置的錯誤對象(Error, SyntaxError, ReferenceError等)以及如何定義自定義錯誤。
  • try to do和try doing的區別,需要死記硬背嗎?
    你們在學校裡上英語課時,一定聽老師講過try的兩種用法吧:①try doing--嘗試做某事;②try to do--盡力做某事老師說這是固定搭配把它們背過。雖然記住了,到實際使用時,卻總是搞混。為什麼會這樣呢?
  • try to do和try doing如何區分
    try to do和try doing在歷年小升初和初中學業水平考試(中考)中,既是重難點,也是很多考生的痛點。往往一聽似懂非懂,一做就錯。今天德叔為大家解密try to do和try doing不為人知的「秘密」。
  • Colbie Caillat: Try
    You don't have to try so hardYou don't have to, give it all awayYou just have to get up, get up, get up, get upYou don't have to change a single thingYou don't have to
  • try to do 和try doing 到底怎麼分辨?
    到底是try to do還是try doing, 總是有同學傻傻分不清楚。那麼我們一起來看一下,以上兩句話有什麼意思的差別嗎?I tried to keep my eyes open.也就是說,try to do表達的是努力去做某件困難的事,但是這件事未必會成功。例句:I tried to lift the heavy box.I tried to find my lost keys.
  • 「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和do one's best的區別
    The difference between "try" or "do one's best" - Alan, China 我想知道try和do one's best之間的區別。我的英語老師告訴我它們是一樣的。但我相信每個詞都有區別。你能幫助我嗎?
  • 又是嘗試又是努力,你知道try與attempt的區別嗎?
    昨天咱們講了try的用法,今天咱們講一下try和attemapt,這兩個單詞(都有嘗試、試圖做某事的意思)的區別:(1) try更接地氣,使用頻率高,意思:①嘗試、②盡力try使用頻率高,更加口語化,根據後面跟的不同形式
  • 「try to please everyone」是什麼意思?
    try to please everyone,儘量取悅所有人,想讓所有人都高興。It is impossible that you wanna try to please everyone.Don't try to please everyone. Just do what you know is right.不要試圖取悅每個人,只要做好自己認為正確的選擇。The key to success is to be you.
  • 《lol手遊》Server is currently under maintenance,please try...
    導 讀 英雄聯盟手遊開測後,國內玩家遇到了很多無法登陸的問題,「Server is currently under maintenance,please try
  • trytodo&trydoing之區別:盡力與嘗試
    怎樣正確應用try to do 和try doing?try to do,盡力做某事,等於try one's best to do sth,未必成功做到。try doing,試著做某事(此前未曾做過),不體現傾力、盡力之意。Examples:He tried to climb Mountain Tai.他竭盡全力,攀登泰山。
  • python編程從入門到實踐:使用try-except代碼塊
    try:number1=int(input("請輸入一個數字:"))number2=int(input("請輸入一個數字:"))print(number1+number2)except ValueError
  • 美國人說「try it on」可不是試穿哦!那是啥?
    我們都知道,try是一個很簡單的詞彙,它不就是嘗試的意思嘛?對!但但但是,小單詞大應用,究竟有哪些你還不會的表達呢?1) "try it on"為何不是試穿?第一個:try it on。很多同學靈機一現,這就是試穿啊!哈,真不是!
  • I will try並不是我盡力試試!外國人是這樣理解的!
    我們都知道try是嘗試,當我們想表達"我會盡力去做",經常會說I will try或I will try my best.但這樣的英文,在外國人聽來,很多時候,並不是你想的這個意思。到底是什麼,我們來看!1、I will try該怎麼翻譯?
  • 學英文多年Try to do和Try doing誰是「嘗試做」!
    Try 試圖 表示給建議、鼓勵,特別是第一次做某事的時候,用Try doing「嘗試做」 You should try eating pasta.
  • 華爾街英語:我試試,你還是只會說「I』ll try」?
    華爾街英語:我試試,你還是只會說「I』ll try」? 中文裡面有許多近義詞,在表達上意思相近,但是情緒上狀態卻不盡相同。
  • 美國人說「nice try」可不是誇你「試得好」!可能內心在翻白眼呢
    這幾個英語口語句子全部都跟try相關。話不多說,幹起來吧!1)「Nice try」到底是個啥?美國人說「nice try」可不是誇你「試得好」!可能內心在翻白眼呢!這種一聽就知道是說謊話,還想要騙你,這個時候就可以諷刺的說nice try或者good try。有種感覺表示厲害厲害,睜著眼睛說瞎話。
  • 中式英語簡單滑稽,但千萬不能寫到試卷上,不信you try try see!
    如果用到考試中,那成績或許會一塌糊塗,不信「you try try see」。
  • TeW try out Elwono Courier strat in 2020
    18183首頁 YouTube TeW try out Elwono Courier strat in 2020 TeW try out Elwono Courier strat in 2020
  • ...Please wait a few minutes and try again.是什麼意思 中文...
    Please wait a few minutes and try again.是什麼意思?許多玩家不太清楚這個英文的意思,下面就讓... lol手遊We've received your request.