優(yōu)雅地處理異常真是一門學(xué)問(wèn)??!-創(chuàng)新互聯(lián)

靜樂(lè)網(wǎng)站建設(shè)公司成都創(chuàng)新互聯(lián),靜樂(lè)網(wǎng)站設(shè)計(jì)制作,有大型網(wǎng)站制作公司豐富經(jīng)驗(yàn)。已為靜樂(lè)成百上千提供企業(yè)網(wǎng)站建設(shè)服務(wù)。企業(yè)網(wǎng)站搭建\成都外貿(mào)網(wǎng)站制作要多少錢,請(qǐng)找那個(gè)售后服務(wù)好的靜樂(lè)做網(wǎng)站的公司定做!

01、前言

你有沒(méi)有這樣的印象,當(dāng)你想要更新一款 APP 的時(shí)候,它的更新日志里總有這么一兩句描述:

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

作為一名負(fù)責(zé)任的程序員,我們當(dāng)然希望程序不會(huì)出現(xiàn) bug,因?yàn)?bug 出現(xiàn)的越多,間接地證明了我們的編程能力越差,至少領(lǐng)導(dǎo)是這么看的。

事實(shí)上,領(lǐng)導(dǎo)是不會(huì)拿自己的腦袋宣言的:“我們的程序絕不存在任何一個(gè) bug?!钡?dāng)程序出現(xiàn) bug 的時(shí)候,領(lǐng)導(dǎo)會(huì)毫不猶豫地選擇讓程序員背鍋。

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

?在編碼階段合理使用異常處理機(jī)制,并記錄日志以備后續(xù)分析?在測(cè)試階段進(jìn)行大量有效的測(cè)試,在用戶發(fā)現(xiàn)錯(cuò)誤之前發(fā)現(xiàn)錯(cuò)誤

還有一點(diǎn)需要做的是,在敲代碼之前,學(xué)習(xí)必要的編程常識(shí),做到兵馬未動(dòng),糧草先行。

02、異常

在 Java 中,異常(Throwable)的層次結(jié)構(gòu)大致如下。

優(yōu)雅地處理異常真是一門學(xué)問(wèn)啊!

Error 類異常描述了 Java 運(yùn)行時(shí)系統(tǒng)的內(nèi)部錯(cuò)誤,比如最常見(jiàn)的?OutOfMemoryError和?NoClassDefFoundError。

導(dǎo)致?OutOfMemoryError的常見(jiàn)原因有以下幾種:

?內(nèi)存中加載的數(shù)據(jù)量過(guò)于龐大,如一次從數(shù)據(jù)庫(kù)取出過(guò)多數(shù)據(jù);?集合中的對(duì)象引用在使用完后未清空,使得 JVM 不能回收;?代碼中存在死循環(huán)或循環(huán)產(chǎn)生過(guò)多重復(fù)的對(duì)象;?啟動(dòng)參數(shù)中內(nèi)存的設(shè)定值過(guò)小;

OutOfMemoryError的解決辦法需要視情況而定,但問(wèn)題的根源在于程序的設(shè)計(jì)不夠合理,需要通過(guò)一些性能檢測(cè)才能找得出引發(fā)問(wèn)題的根源。

導(dǎo)致?NoClassDefFoundError的原因只有一個(gè),Java 虛擬機(jī)在編譯時(shí)能找到類,而在運(yùn)行時(shí)卻找不到。

優(yōu)雅地處理異常真是一門學(xué)問(wèn)?。?></p><p><code>NoClassDefFoundError</code>的解決辦法,我截了一張圖,如上所示。當(dāng)一個(gè)項(xiàng)目引用了另外一個(gè)項(xiàng)目時(shí),切記這一步!</p><p>Exception(例外)通常可分為兩類,一類是寫代碼的人造成的,比如訪問(wèn)空指針(<code>NullPointerException</code>)。應(yīng)當(dāng)在敲代碼的時(shí)候進(jìn)行檢查,以杜絕這類異常的發(fā)生。</p><ul><li><p></p></li><li><p></p></li></ul><pre>if?(str?==?null?||?

另外一類異常不是寫代碼的人造成的,要么需要拋出,要么需要捕獲,比如說(shuō)常見(jiàn)的?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

當(dāng)拋出異常的時(shí)候,剩余的代碼就會(huì)終止執(zhí)行,這時(shí)候一些資源就需要主動(dòng)回收。Java 的解決方案就是?finally子句——不管異常有沒(méi)有被捕獲,finally子句里的代碼都會(huì)執(zhí)行。

在下面的示例當(dāng)中,輸入流將會(huì)被關(guān)閉,以釋放資源。

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();????}}

但我總覺(jué)得這樣的設(shè)計(jì)有點(diǎn)問(wèn)題,因?yàn)?close()方法同樣會(huì)拋出?IOException

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

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

選擇前一種就會(huì)讓?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();????}}

選擇后一種會(huì)讓代碼看起來(lái)很臃腫,就像下面這樣。

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();????????}????}}

總之,我們需要另外一種更優(yōu)雅的解決方案。JDK7 新增了?Try-With-Resource語(yǔ)法:如果一個(gè)類(比如?InputStream)實(shí)現(xiàn)了?AutoCloseable接口,那么就可以將該類的對(duì)象創(chuàng)建在?try關(guān)鍵字后面的括號(hào)中,當(dāng)?try-catch代碼塊執(zhí)行完畢后,Java 會(huì)確保該對(duì)象的?close方法被調(diào)用。示例如下。

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、建議

關(guān)于異常處理機(jī)制的使用,我這里總結(jié)了一些非常實(shí)用的建議,希望你能夠采納。

1)盡量捕獲原始的異常

實(shí)際應(yīng)該捕獲?FileNotFoundException,卻捕獲了泛化的?Exception。示例如下。

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

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

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

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

當(dāng)異常發(fā)生時(shí)打印它,然后重新拋出它,以便調(diào)用者能夠適當(dāng)?shù)靥幚硭>拖裣旅孢@段代碼一樣。

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

這似乎考慮得很周全,但是這樣做的壞處是調(diào)用者可能也打印了異常,重復(fù)的打印信息會(huì)增添排查問(wèn)題的難度。

java.io.FileNotFoundException:?沉默王二.txt?(系統(tǒng)找不到指定的文件。)????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?(系統(tǒng)找不到指定的文件。)????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)千萬(wàn)不要用異常處理機(jī)制代替判斷

我曾見(jiàn)過(guò)類似下面這樣奇葩的代碼,本來(lái)應(yīng)該判?null的,結(jié)果使用了異常處理機(jī)制來(lái)代替。

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

捕獲異常相對(duì)判斷花費(fèi)的時(shí)間要多得多!我們可以模擬兩個(gè)代碼片段來(lái)對(duì)比一下。

代碼片段 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 萬(wàn)次的循環(huán),代碼片段 A(異常處理機(jī)制)執(zhí)行的時(shí)間大概需要 1983 毫秒;代碼片段 B(正常判斷)執(zhí)行的時(shí)間大概只需要 1 毫秒。這樣的比較雖然不夠精確,但足以說(shuō)明問(wèn)題。

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

如果盲目地過(guò)早捕獲異常的話,通常會(huì)導(dǎo)致更嚴(yán)重的錯(cuò)誤和其他異常。請(qǐng)看下面的例子。

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(); ?}}

假如文件沒(méi)有找到的話,InputStream的對(duì)象引用 is 就為?null,新的?NullPointerException就會(huì)出現(xiàn)。

java.io.FileNotFoundException:?沉默王二.txt?(系統(tǒng)找不到指定的文件。)????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并不是程序出現(xiàn)問(wèn)題的本因,但實(shí)際上它出現(xiàn)了,無(wú)形當(dāng)中干擾了我們的視線。正確的做法是延遲捕獲異常,讓程序在第一個(gè)異常捕獲后就終止執(zhí)行。

05、最后

好了,關(guān)于異常我們就說(shuō)到這。異常處理是程序開(kāi)發(fā)中必不可少的操作之一,但如何正確優(yōu)雅地對(duì)異常進(jìn)行處理卻是一門學(xué)問(wèn),好的異常處理機(jī)制可以確保程序的健壯性,提高系統(tǒng)的可用率。

創(chuàng)新互聯(lián)www.cdcxhl.cn,專業(yè)提供香港、美國(guó)云服務(wù)器,動(dòng)態(tài)BGP最優(yōu)骨干路由自動(dòng)選擇,持續(xù)穩(wěn)定高效的網(wǎng)絡(luò)助力業(yè)務(wù)部署。公司持有工信部辦法的idc、isp許可證, 機(jī)房獨(dú)有T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確進(jìn)行流量調(diào)度,確保服務(wù)器高可用性。佳節(jié)活動(dòng)現(xiàn)已開(kāi)啟,新人活動(dòng)云服務(wù)器買多久送多久。

網(wǎng)站名稱:優(yōu)雅地處理異常真是一門學(xué)問(wèn)??!-創(chuàng)新互聯(lián)
URL網(wǎng)址:http://muchs.cn/article12/dsehdc.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供軟件開(kāi)發(fā)、網(wǎng)站建設(shè)、企業(yè)網(wǎng)站制作網(wǎng)頁(yè)設(shè)計(jì)公司App開(kāi)發(fā)、品牌網(wǎng)站建設(shè)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

成都網(wǎng)站建設(shè)公司