日韩久久久精品,亚洲精品久久久久久久久久久,亚洲欧美一区二区三区国产精品 ,一区二区福利

java異常

系統(tǒng) 2027 0

e.printStackTrace();

本文從Java異常最基本的概念、語(yǔ)法開(kāi)始講述了Java異常處理的基本知識(shí),分析了Java異常體系結(jié)構(gòu),對(duì)比Spring的異常處理框 架,闡述了異常處理的基本原則。并且作者提出了自己處理一個(gè)大型應(yīng)用系統(tǒng)異常的思想,并通過(guò)設(shè)計(jì)一個(gè)異常處理的框架來(lái)論述此思想。
一、 異常的概念和Java異常體系結(jié)構(gòu)


異常是程序運(yùn)行過(guò)程中出現(xiàn)的錯(cuò)誤。本文主要講授的是Java語(yǔ)言的異常處理。Java語(yǔ)言的異常處理框架,是Java語(yǔ)言健壯性的一個(gè)重要體現(xiàn)。


Java把異常當(dāng)作對(duì)象來(lái)處理,并定義一個(gè)基類java.lang.Throwable作為所有異常的超類。在Java API中已經(jīng)定義了許多異常類,這些異常類分為兩大類,錯(cuò)誤Error和異常Exception。Java異常體系結(jié)構(gòu)呈樹(shù)狀,其層次結(jié)構(gòu)圖如圖 1所示:

java異常


圖 1 Java異常體系結(jié)構(gòu)

Thorwable類所有異常和錯(cuò)誤的超類,有兩個(gè)子類Error和Exception,分別表示錯(cuò)誤和異常。其中異常類Exception又分為 運(yùn)行時(shí)異常(RuntimeException)和非運(yùn)行時(shí)異常,這兩種異常有很大的區(qū)別,也稱之為不檢查異常(Unchecked Exception)和檢查異常(Checked Exception)。下面將詳細(xì)講述這些異常之間的區(qū)別與聯(lián)系:


1、Error與Exception Error是程序無(wú)法處理的錯(cuò)誤,比如OutOfMemoryError、ThreadDeath等。這些異常發(fā)生時(shí),Java虛擬機(jī)(JVM)一般會(huì)選擇線程終止。
Exception是程序本身可以處理的異常,這種異常分兩大類運(yùn)行時(shí)異常和非運(yùn)行時(shí)異常。程序中應(yīng)當(dāng)盡可能去處理這些異常。

2、運(yùn)行時(shí)異常和非運(yùn)行時(shí)異常

運(yùn)行時(shí)異常都是RuntimeException類及其子類異常,如NullPointerException、 IndexOutOfBoundsException等,這些異常是不檢查異常,程序中可以選擇捕獲處理,也可以不處理。這些異常一般是由程序邏輯錯(cuò)誤引 起的,程序應(yīng)該從邏輯角度盡可能避免這類異常的發(fā)生。

非運(yùn)行時(shí)異常是RuntimeException以外的異常,類型上都屬于Exception類及其子類。從程序語(yǔ)法角度講是必須進(jìn)行處理的異常,如果不 處理,程序就不能編譯通過(guò)。如IOException、SQLException等以及用戶自定義的Exception異常,一般情況下不自定義檢查異 常。

二、 異常的捕獲和處理

Java異常的捕獲和處理是一個(gè)不容易把握的事情,如果處理不當(dāng),不但會(huì)讓程序代碼的可讀性大大降低,而且導(dǎo)致系統(tǒng)性能低下,甚至引發(fā)一些難以發(fā)現(xiàn)的錯(cuò)誤。

Java異常處理涉及到五個(gè)關(guān)鍵字,分別是:try、catch、finally、throw、throws。下面將驟一介紹,通過(guò)認(rèn)識(shí)這五個(gè)關(guān)鍵字,掌握基本異常處理知識(shí)。

1、 異常處理的基本語(yǔ)法
在java中,異常處理的完整語(yǔ)法是:
try{
//(嘗試運(yùn)行的)程序代碼
}catch(異常類型 異常的變量名){
//異常處理代碼
}finally{
//異常發(fā)生,方法返回之前,總是要執(zhí)行的代碼
}

以上語(yǔ)法有三個(gè)代碼塊:
try語(yǔ)句塊,表示要嘗試運(yùn)行代碼,try語(yǔ)句塊中代碼受異常監(jiān)控,其中代碼發(fā)生異常時(shí),會(huì)拋出異常對(duì)象。


catch語(yǔ)句塊會(huì)捕獲try代碼塊中發(fā)生的異常并在其代碼塊中做異常處理,catch語(yǔ)句帶一個(gè)Throwable類型的參數(shù),表示可捕獲異常類型。當(dāng) try中出現(xiàn)異常時(shí),catch會(huì)捕獲到發(fā)生的異常,并和自己的異常類型匹配,若匹配,則執(zhí)行catch塊中代碼,并將catch塊參數(shù)指向所拋的異常對(duì) 象。catch語(yǔ)句可以有多個(gè),用來(lái)匹配多個(gè)中的一個(gè)異常,一旦匹配上后,就不再嘗試匹配別的catch塊了。通過(guò)異常對(duì)象可以獲取異常發(fā)生時(shí)完整的 JVM堆棧信息,以及異常信息和異常發(fā)生的原因等。

finally語(yǔ)句塊是緊跟catch語(yǔ)句后的語(yǔ)句塊,這個(gè)語(yǔ)句塊總是會(huì)在方法返回前執(zhí)行,而不管是否try語(yǔ)句塊是否發(fā)生異常。并且這個(gè)語(yǔ)句塊總是在方 法返回前執(zhí)行。目的是給程序一個(gè)補(bǔ)救的機(jī)會(huì)。這樣做也體現(xiàn)了Java語(yǔ)言的健壯性。 2、 try、catch、finally三個(gè)語(yǔ)句塊應(yīng)注意的問(wèn)題
第一、try、catch、finally三個(gè)語(yǔ)句塊均不能單獨(dú)使用,三者可以組成 try...catch...finally、try...catch、try...finally三種結(jié)構(gòu),catch語(yǔ)句可以有一個(gè)或多個(gè),finally語(yǔ)句最多一個(gè)。
第二、try、catch、finally三個(gè)代碼塊中變量的作用域?yàn)榇a塊內(nèi)部,分別獨(dú)立而不能相互訪問(wèn)。如果要在三個(gè)塊中都可以訪問(wèn),則需要將變量定義到這些塊的外面。
第三、多個(gè)catch塊時(shí)候,只會(huì)匹配其中一個(gè)異常類并執(zhí)行catch塊代碼,而不會(huì)再執(zhí)行別的catch塊,并且匹配catch語(yǔ)句的順序是由上到下。

3、throw、throws關(guān)鍵字
throw關(guān)鍵字是用于方法體內(nèi)部,用來(lái)拋出一個(gè)Throwable類型的異常。如果拋出了檢查異常,則還應(yīng)該在方法頭部聲明方法可能拋出的異常類型。該 方法的調(diào)用者也必須檢查處理拋出的異常。如果所有方法都層層上拋獲取的異常,最終JVM會(huì)進(jìn)行處理,處理也很簡(jiǎn)單,就是打印異常消息和堆棧信息。如果拋出 的是Error或RuntimeException,則該方法的調(diào)用者可選擇處理該異常。有關(guān)異常的轉(zhuǎn)譯會(huì)在下面說(shuō)明。 throws關(guān)鍵字用于方法體外部的方法聲明部分,用來(lái)聲明方法可能會(huì)拋出某些異常。僅當(dāng)拋出了檢查異常,該方法的調(diào)用者才必須處理或者重新拋出該異常。 當(dāng)方法的調(diào)用者無(wú)力處理該異常的時(shí)候,應(yīng)該繼續(xù)拋出,而不是囫圇吞棗一般在catch塊中打印一下堆棧信息做個(gè)勉強(qiáng)處理。下面給出一個(gè)簡(jiǎn)單例子,看看如何 使用這兩個(gè)關(guān)鍵字:
public static void test3() throws Exception{
//拋出一個(gè)檢查異常
throw new Exception("方法test3中的Exception");
}
3、 Throwable類中的常用方法
getCause():返回拋出異常的原因。如果 cause 不存在或未知,則返回 null。
getMessage():返回異常的消息信息。
printStackTrace():對(duì)象的堆棧跟蹤輸出至錯(cuò)誤輸出流,作為字段 System.err 的值。

三、 異常處理的一般原則

1、 能處理就早處理,拋出不去還不能處理的就想法消化掉或者轉(zhuǎn)換為RuntimeException處理。因?yàn)閷?duì)于一個(gè)應(yīng)用系統(tǒng)來(lái)說(shuō),拋出大量異常是有問(wèn)題的,應(yīng)該從程序開(kāi)發(fā)角度盡可能的控制異常發(fā)生的可能。
2、 對(duì)于檢查異常,如果不能行之有效的處理,還不如轉(zhuǎn)換為RuntimeException拋出。這樣也讓上層的代碼有選擇的余地――可處理也可不處理。
3、 對(duì)于一個(gè)應(yīng)用系統(tǒng)來(lái)說(shuō),應(yīng)該有自己的一套異常處理框架,這樣當(dāng)異常發(fā)生時(shí),也能得到統(tǒng)一的處理風(fēng)格,將優(yōu)雅的異常信息反饋給用戶。

四、 異常的轉(zhuǎn)譯與異常鏈
1、異常轉(zhuǎn)譯的原理

所謂的異常轉(zhuǎn)譯就是將一種異常轉(zhuǎn)換另一種新的異常,也許這種新的異常更能準(zhǔn)確表達(dá)程序發(fā)生異常。

在Java中有個(gè)概念就是異常原因,異常原因?qū)е庐?dāng)前拋出異常的那個(gè)異常對(duì)象,幾乎所有帶異常原因的異常構(gòu)造方法都使用Throwable類型做參數(shù),這 也就為異常的轉(zhuǎn)譯提供了直接的支持,因?yàn)槿魏涡问降漠惓:湾e(cuò)誤都是Throwable的子類。比如將SQLException轉(zhuǎn)換為另外一個(gè)新的異常 DAOException,可以這么寫(xiě):

先自定義一個(gè)異常DAOException:

public class DAOException extends RuntimeException {
//(省略了部分代碼)
public DAOException(String message, Throwable cause) {
super(message, cause);
}
}
比如有一個(gè)SQLException類型的異常對(duì)象e,要轉(zhuǎn)換為DAOException,可以這么寫(xiě):


DAOException daoEx = new DAOException ( "SQL異常", e);


異常轉(zhuǎn)譯是針對(duì)所有繼承Throwable超類的類而言的,從編程的語(yǔ)法角度講,其子類之間都可以相互轉(zhuǎn)換。但是,從合理性和系統(tǒng)設(shè)計(jì)角度考慮,可將異常 分為三類:Error、Exception、RuntimeException,筆者認(rèn)為,合理的轉(zhuǎn)譯關(guān)系圖應(yīng)該如圖 2: java異常


圖 2 異常轉(zhuǎn)譯

為什么要這么做呢?筆者認(rèn)為,異常的處理存在著一套哲學(xué)思想:對(duì)于一個(gè)應(yīng)用系統(tǒng)來(lái)說(shuō),系統(tǒng)所發(fā)生的任何異常或者錯(cuò)誤對(duì)操作用戶來(lái)說(shuō)都是系統(tǒng)"運(yùn)行時(shí)"異 常,都是這個(gè)應(yīng)用系統(tǒng)內(nèi)部的異常。這也是異常轉(zhuǎn)譯和應(yīng)用系統(tǒng)異常框架設(shè)計(jì)的指導(dǎo)原則。在系統(tǒng)中大量處理非檢查異常的負(fù)面影響很多,最重要的一個(gè)方面就是代 碼可讀性降低,程序編寫(xiě)復(fù)雜,異常處理的代碼也很蒼白無(wú)力。因此,很有必要將這些檢查異常Exception和錯(cuò)誤Error轉(zhuǎn)換為 RuntimeException異常,讓程序員根據(jù)情況來(lái)決定是否捕獲和處理所發(fā)生的異常。

圖中的三條線標(biāo)識(shí)轉(zhuǎn)換的方向,分三種情況:

①:Error到Exception:將錯(cuò)誤轉(zhuǎn)換為異常,并繼續(xù)拋出。例如Spring WEB框架中,將org.springframework.web.servlet.DispatcherServlet的doDispatch()方法 中,將捕獲的錯(cuò)誤轉(zhuǎn)譯為一個(gè)NestedServletException異常。這樣做的目的是為了最大限度挽回因錯(cuò)誤發(fā)生帶來(lái)的負(fù)面影響。因?yàn)橐粋€(gè) Error常常是很?chē)?yán)重的錯(cuò)誤,可能會(huì)引起系統(tǒng)掛起。

②:Exception到RuntimeException:將檢查異常轉(zhuǎn)換為RuntimeException可以讓程序代碼變得更優(yōu)雅,讓開(kāi)發(fā)人員集中經(jīng)理設(shè)計(jì)更合理的程序代碼,反過(guò)來(lái)也增加了系統(tǒng)發(fā)生異常的可能性。

③:Error到RuntimeException:目的還是一樣的。把所有的異常和錯(cuò)誤轉(zhuǎn)譯為不檢查異常,這樣可以讓代碼更為簡(jiǎn)潔,還有利于對(duì)錯(cuò)誤和異常信息的統(tǒng)一處理。

1、 異常鏈

異常鏈顧名思義就是將異常發(fā)生的原因一個(gè)傳一個(gè)串起來(lái),即把底層的異常信息傳給上層,這樣逐層拋出。Java API文檔中給出了一個(gè)簡(jiǎn)單的模型:

try {
lowLevelOp();
} catch (LowLevelException le) {
throw (HighLevelException)
new HighLevelException().initCause(le);
}

當(dāng)程序捕獲到了一個(gè)底層異常le,在處理部分選擇了繼續(xù)拋出一個(gè)更高級(jí)別的新異常給此方法的調(diào)用者。這樣異常的原因就會(huì)逐層傳遞。這樣,位于高層的異常遞 歸調(diào)用getCause()方法,就可以遍歷各層的異常原因。這就是Java異常鏈的原理。異常鏈的實(shí)際應(yīng)用很少,發(fā)生異常時(shí)候逐層上拋不是個(gè)好注意,上 層拿到這些異常又能奈之何?而且異常逐層上拋會(huì)消耗大量資源,因?yàn)橐4嬉粋€(gè)完整的異常鏈信息。

五、 設(shè)計(jì)一個(gè)高效合理的異常處理框架

對(duì)于一個(gè)應(yīng)用系統(tǒng)來(lái)說(shuō),發(fā)生所有異常在用戶看來(lái)都是應(yīng)用系統(tǒng)內(nèi)部的異常。因此應(yīng)該設(shè)計(jì)一套應(yīng)用系統(tǒng)的異常框架,以處理系統(tǒng)運(yùn)行過(guò)程中的所有異常。

基于這種觀點(diǎn),可以設(shè)計(jì)一個(gè)應(yīng)用系統(tǒng)的異常比如叫做AppException。并且對(duì)用戶來(lái)說(shuō),這些異常都是運(yùn)行應(yīng)用系統(tǒng)運(yùn)行時(shí)發(fā)生的,因此 AppException應(yīng)該繼承RuntimeException,這樣系統(tǒng)中所有的其他異常都轉(zhuǎn)譯為AppException,當(dāng)異常發(fā)生的時(shí)候,前 端接收到AppExcetpion并做統(tǒng)一的處理。畫(huà)出異常處理框架如圖 3 : java異常

圖 3 一個(gè)應(yīng)用系統(tǒng)的異常處理框架

在這個(gè)設(shè)計(jì)圖中,AppRuntimeException是系統(tǒng)異常的基類,對(duì)外只拋出這個(gè)異常,這個(gè)異常可以由前端(客戶端)接收處理,當(dāng)異常發(fā)生時(shí),客戶端的相關(guān)組件捕獲并處理這些異常,將"友好"的信息展示給客戶。
在AppRuntimeException下層,有各種各樣的異常和錯(cuò)誤,最終都轉(zhuǎn)譯為 AppRuntimeException,AppRuntimeException下面還可以設(shè)計(jì)一些別的子類異常,比如 AppDAOException、OtherException等,這些都根據(jù)實(shí)際需要靈活處理。在往下就是如何將捕獲的原始異常比如 SQLException、HibernateException轉(zhuǎn)換為更高級(jí)一點(diǎn)AppDAOException。

有關(guān)異常框架設(shè)計(jì)這方面公認(rèn)比較好的就是Spring,Spring中的所有異常都可以用 org.springframework.core.NestedRuntimeException來(lái)表示,并且該基類繼承的是 RuntimeException。Spring框架很龐大,因此設(shè)計(jì)了很多NestedRuntimeException的子類,還有異常轉(zhuǎn)換的工具, 這些都是非常優(yōu)秀的設(shè)計(jì)思想。

六、 Java異常處理總結(jié)

回顧全文,總結(jié)一下Java異常處理的要點(diǎn):

1、 異常是程序運(yùn)行過(guò)程過(guò)程出現(xiàn)的錯(cuò)誤,在Java中用類來(lái)描述,用對(duì)象來(lái)表示具體的異常。Java將其區(qū)分為Error與Exception,Error是程序無(wú)力處理的錯(cuò)誤,Exception是程序可以處理的錯(cuò)誤。異常處理是為了程序的健壯性。
2、 Java異常類來(lái)自于Java API定義和用戶擴(kuò)展。通過(guò)繼承Java API異常類可以實(shí)現(xiàn)異常的轉(zhuǎn)譯。
3、 異常能處理就處理,不能處理就拋出,最終沒(méi)有處理的異常JVM會(huì)進(jìn)行處理。
4、 異常可以傳播,也可以相互轉(zhuǎn)譯,但應(yīng)該根據(jù)需要選擇合理的異常轉(zhuǎn)譯的方向。
5、 對(duì)于一個(gè)應(yīng)用系統(tǒng),設(shè)計(jì)一套良好的異常處理體系很重要。這一點(diǎn)在系統(tǒng)設(shè)計(jì)的時(shí)候就應(yīng)該考慮到。


java異常


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號(hào)聯(lián)系: 360901061

您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對(duì)您有幫助就好】

您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長(zhǎng)會(huì)非常 感謝您的哦!!!

發(fā)表我的評(píng)論
最新評(píng)論 總共0條評(píng)論
主站蜘蛛池模板: 科尔| 杨浦区| 榕江县| 泌阳县| 襄樊市| 南充市| 浦城县| 四会市| 忻城县| 连南| 板桥市| 洞头县| 九江县| 汤原县| 长海县| 连南| 绥德县| 永安市| 外汇| 五峰| 徐汇区| 全南县| 新巴尔虎左旗| 华亭县| 安国市| 美姑县| 罗源县| 西吉县| 东山县| 晋江市| 柳州市| 寻甸| 湖口县| 德清县| 晋宁县| 略阳县| 河津市| 滦平县| 扬中市| 康平县| 阿图什市|