亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

優雅地處理異常真是一門學問啊!

發布時間:2020-07-27 17:35:13 來源:網絡 閱讀:190 作者:沉默王二 欄目:編程語言

優雅地處理異常真是一門學問啊!cdn.xitu.io/2019/5/8/16a95746dbe817ca?w=900&h=500&f=jpeg&s=37914">

01、前言

你有沒有這樣的印象,當你想要更新一款 APP 的時候,它的更新日志里總有這么一兩句描述:

?修復若干 bug?殺了某程序員祭天,并成功解決掉他遺留的 bug

作為一名負責任的程序員,我們當然希望程序不會出現 bug,因為 bug 出現的越多,間接地證明了我們的編程能力越差,至少領導是這么看的。

事實上,領導是不會拿自己的腦袋宣言的:“我們的程序絕不存在任何一個 bug。”但當程序出現 bug 的時候,領導會毫不猶豫地選擇讓程序員背鍋。

為了讓自己少背鍋,我們可以這樣做:

?在編碼階段合理使用異常處理機制,并記錄日志以備后續分析?在測試階段進行大量有效的測試,在用戶發現錯誤之前發現錯誤

還有一點需要做的是,在敲代碼之前,學習必要的編程常識,做到兵馬未動,糧草先行。

02、異常

在 Java 中,異常(Throwable)的層次結構大致如下。

優雅地處理異常真是一門學問啊!

Error 類異常描述了 Java 運行時系統的內部錯誤,比如最常見的?OutOfMemoryError?和?NoClassDefFoundError

導致?OutOfMemoryError?的常見原因有以下幾種:

?內存中加載的數據量過于龐大,如一次從數據庫取出過多數據;?集合中的對象引用在使用完后未清空,使得 JVM 不能回收;?代碼中存在死循環或循環產生過多重復的對象;?啟動參數中內存的設定值過小;

OutOfMemoryError?的解決辦法需要視情況而定,但問題的根源在于程序的設計不夠合理,需要通過一些性能檢測才能找得出引發問題的根源。

導致?NoClassDefFoundError?的原因只有一個,Java 虛擬機在編譯時能找到類,而在運行時卻找不到。

優雅地處理異常真是一門學問啊!

NoClassDefFoundError?的解決辦法,我截了一張圖,如上所示。當一個項目引用了另外一個項目時,切記這一步!

Exception(例外)通常可分為兩類,一類是寫代碼的人造成的,比如訪問空指針(NullPointerException)。應當在敲代碼的時候進行檢查,以杜絕這類異常的發生。



if?(str?==?null?||?"".eqauls(str))?{}

另外一類異常不是寫代碼的人造成的,要么需要拋出,要么需要捕獲,比如說常見的?IOException

拋出的示例。








public static void main(String[] args) throws IOException { ? ?InputStream is = new FileInputStream("沉默王二.txt"); ? ?int b; ? ?while ((b = is.read()) != -1) {
? ?}}

捕獲的示例。












public static void main(String[] args) { ? ?try { ? ? ? ?InputStream is = new FileInputStream("沉默王二.txt"); ? ? ? ?int b; ? ? ? ?while((b = is.read()) != -1) {
? ? ? ?} ? ?} catch (IOException e) { ? ? ? ?e.printStackTrace(); ? ?}}

03、finally

當拋出異常的時候,剩余的代碼就會終止執行,這時候一些資源就需要主動回收。Java 的解決方案就是?finally?子句——不管異常有沒有被捕獲,finally?子句里的代碼都會執行。

在下面的示例當中,輸入流將會被關閉,以釋放資源。













public?static?void?main(String[]?args)?{????InputStream?is?=?null;????try?{????????is?=?new?FileInputStream("沉默王二.txt");????????int?b;????????while?((b?=?is.read())?!=?-1)?{}????}?catch?(IOException?e)?{????????e.printStackTrace();????}?finally?{????????is.close();????}}

但我總覺得這樣的設計有點問題,因為?close()?方法同樣會拋出?IOException


????public?void?close()?throws?IOException?{}

也就是說,調用?close()?的 main 方法要么需要拋出?IOException,要么需要在?finally?子句里重新捕獲?IOException

選擇前一種就會讓?try catch?略顯尷尬,就像下面這樣。













public?static?void?main(String[]?args)?throws?IOException?{????InputStream?is?=?null;????try?{????????is?=?new?FileInputStream("沉默王二.txt");????????int?b;????????while?((b?=?is.read())?!=?-1)?{}????}?catch?(IOException?e)?{????????e.printStackTrace();????}?finally?{????????is.close();????}}

選擇后一種會讓代碼看起來很臃腫,就像下面這樣。

















public?static?void?main(String[]?args)?{????InputStream?is?=?null;????try?{????????is?=?new?FileInputStream("沉默王二.txt");????????int?b;????????while?((b?=?is.read())?!=?-1)?{}????}?catch?(IOException?e)?{????????e.printStackTrace();????}?finally?{????????try?{????????????is.close();????????}?catch?(IOException?e)?{????????????e.printStackTrace();????????}????}}

總之,我們需要另外一種更優雅的解決方案。JDK7 新增了?Try-With-Resource?語法:如果一個類(比如?InputStream)實現了?AutoCloseable?接口,那么就可以將該類的對象創建在?try?關鍵字后面的括號中,當?try-catch?代碼塊執行完畢后,Java 會確保該對象的?close方法被調用。示例如下。










public?static?void?main(String[]?args)?{????try?(InputStream?is?=?new?FileInputStream("沉默王二.txt"))?{????????int?b;????????while?((b?=?is.read())?!=?-1)?{????????}????}?catch?(IOException?e)?{????????e.printStackTrace();????}}

04、建議

關于異常處理機制的使用,我這里總結了一些非常實用的建議,希望你能夠采納。

1)盡量捕獲原始的異常

實際應該捕獲?FileNotFoundException,卻捕獲了泛化的?Exception。示例如下。







InputStream?is?=?null;try?{????is?=?new?FileInputStream("沉默王二.txt");}?catch?(Exception?e)?{????e.printStackTrace();}

這樣做的壞處顯而易見:假如你喊“王二”,那么我就敢答應;假如你喊“老王”,那么我還真不敢答應,萬一你喊的我妹妹“王三”呢?

很多初學者誤以為捕獲泛化的?Exception?更省事,但也更容易讓人“丈二和尚摸不著頭腦”。相反,捕獲原始的異常能夠讓協作者更輕松地辨識異常類型,更容易找出問題的根源。

2)盡量不要打印堆棧后再拋出異常

當異常發生時打印它,然后重新拋出它,以便調用者能夠適當地處理它。就像下面這段代碼一樣。








public?static?void?main(String[]?args)?throws?IOException?{????try?(InputStream?is?=?new?FileInputStream("沉默王二.txt"))?{????}catch?(IOException?e)?{????????e.printStackTrace();????????throw?e;????}?}

這似乎考慮得很周全,但是這樣做的壞處是調用者可能也打印了異常,重復的打印信息會增添排查問題的難度。













java.io.FileNotFoundException:?沉默王二.txt?(系統找不到指定的文件。)????at?java.io.FileInputStream.open0(Native?Method)????at?java.io.FileInputStream.open(FileInputStream.java:195)????at?java.io.FileInputStream.<init>(FileInputStream.java:138)????at?java.io.FileInputStream.<init>(FileInputStream.java:93)????at?learning.Test.main(Test.java:10)Exception?in?thread?"main"?java.io.FileNotFoundException:?沉默王二.txt?(系統找不到指定的文件。)????at?java.io.FileInputStream.open0(Native?Method)????at?java.io.FileInputStream.open(FileInputStream.java:195)????at?java.io.FileInputStream.<init>(FileInputStream.java:138)????at?java.io.FileInputStream.<init>(FileInputStream.java:93)????at?learning.Test.main(Test.java:10)

3)千萬不要用異常處理機制代替判斷

我曾見過類似下面這樣奇葩的代碼,本來應該判?null?的,結果使用了異常處理機制來代替。









public?static?void?main(String[]?args)?{????try?{????????String?str?=?null;????????String[]?strs?=?str.split(",");????}?catch?(NullPointerException?e)?{????????e.printStackTrace();????}}

捕獲異常相對判斷花費的時間要多得多!我們可以模擬兩個代碼片段來對比一下。

代碼片段 A:











long?a?=?System.currentTimeMillis();for?(int?i?=?0;?i?<?100000;?i++)?{????try?{????????String?str?=?null;????????String[]?strs?=?str.split(",");????}?catch?(NullPointerException?e)?{????}}long?b?=?System.currentTimeMillis();System.out.println(b?-?a);

代碼片段 B:










long?a?=?System.currentTimeMillis();for?(int?i?=?0;?i?<?100000;?i++)?{????String?str?=?null;????if?(str?!=?null)?{????????String[]?strs?=?str.split(",");????}}long?b?=?System.currentTimeMillis();System.out.println(b?-?a);

100000 萬次的循環,代碼片段 A(異常處理機制)執行的時間大概需要 1983 毫秒;代碼片段 B(正常判斷)執行的時間大概只需要 1 毫秒。這樣的比較雖然不夠精確,但足以說明問題。

4)不要盲目地過早捕獲異常

如果盲目地過早捕獲異常的話,通常會導致更嚴重的錯誤和其他異常。請看下面的例子。
























InputStream is = null;try { ? ?is = new FileInputStream("沉默王二.txt");
} catch (FileNotFoundException e) { ? ?e.printStackTrace();}
int b;try { ? ?while ((b = is.read()) != -1) { ? ?}} catch (IOException e) { ? ?e.printStackTrace();}
finally { ? ?try { ? ? ? ?is.close(); ? ?} catch (IOException e) { ? ? ? ?e.printStackTrace(); ? ?}}

假如文件沒有找到的話,InputStream?的對象引用 is 就為?null,新的?NullPointerException?就會出現。









java.io.FileNotFoundException:?沉默王二.txt?(系統找不到指定的文件。)????at?java.io.FileInputStream.open0(Native?Method)????at?java.io.FileInputStream.open(FileInputStream.java:195)????at?java.io.FileInputStream.<init>(FileInputStream.java:138)????at?java.io.FileInputStream.<init>(FileInputStream.java:93)????at?learning.Test.main(Test.java:12)Exception?in?thread?"main"?java.lang.NullPointerException????at?learning.Test.main(Test.java:28)

NullPointerException?并不是程序出現問題的本因,但實際上它出現了,無形當中干擾了我們的視線。正確的做法是延遲捕獲異常,讓程序在第一個異常捕獲后就終止執行。

05、最后

好了,關于異常我們就說到這。異常處理是程序開發中必不可少的操作之一,但如何正確優雅地對異常進行處理卻是一門學問,好的異常處理機制可以確保程序的健壯性,提高系統的可用率。


向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

孝感市| 永城市| 隆回县| 南溪县| 清苑县| 威宁| 陆良县| 内丘县| 定襄县| 古交市| 丹凤县| 金阳县| 富裕县| 红原县| 临海市| 吴忠市| 绥滨县| 罗定市| 马龙县| 孟连| 洮南市| 德格县| 容城县| 岑溪市| 资中县| 万州区| 富川| 永年县| 嘉义市| 化隆| 秀山| 绥德县| 武隆县| 通河县| 兴仁县| 綦江县| 文水县| 芷江| 德化县| 赞皇县| 册亨县|