Java異常

本文將向讀者介紹如何編寫正確的異常處理程序扛稽,并將展示當(dāng)方法出問題的時候柴灯,如何產(chǎn)生自定義異常物延。如有不對歡迎拍磚宣旱,謝謝。

文章出處

文章出自:安卓進(jìn)階學(xué)習(xí)指南
主要貢獻(xiàn)者:
justdoitJX
YangZhe
Milo

問題

  • 什么是異常叛薯,異常的分類有哪些浑吟?
  • RuntimeException和CheckedException的區(qū)別、error和exception的區(qū)別?
  • 常見RuntimeException(運(yùn)行時異常)和CheckedException(檢查型異常)有哪些耗溜?
  • 異常的機(jī)制(異常處理的流程)买置?
  • 異常的使用方法(如何拋出異常,如何捕獲異常强霎,再次拋出異常)?
  • throws,throw,try,catch,finally分別代表什么意義忿项?
  • 什么是“異常鏈”?
  • 怎么自定義異常?
  • Java異常類有哪些的重要方法?

什么是異常

異常是發(fā)生在程序執(zhí)行過程中阻礙程序正常執(zhí)行的錯誤事件轩触;比如打開的文件不存在寞酿、網(wǎng)絡(luò)連接中斷、操作數(shù)組越界等都會導(dǎo)致出現(xiàn)異常脱柱。

異常的分類

Throwable.png

異常的基類為Throwable伐弹,Error和Exception繼承Throwable。

Error(錯誤):是程序無法處理的錯誤榨为。這些錯誤表示故障發(fā)生于虛擬機(jī)自身惨好、或者發(fā)生在虛擬機(jī)試圖執(zhí)行應(yīng)用時,一般不需要程序處理随闺。

Exception:這種異常分兩大類RuntimeException(運(yùn)行時異常)和CheckedException(編譯時異常);

常見的RuntimeException有:

ArrayIndexOutOfBoundsException(數(shù)組索引越界異常)
NullPointerException(空指針異常)
ClassNotFoundException(找不到類異常)
IllegalArgumentException(非法參數(shù)異常)
SecurityException(安全性異常)

常見的CheckedException有:

NoSuchMethodException(方法未找到拋出的異常)
ClassCastException(類型轉(zhuǎn)換異常類)
NumberFormatException(字符串轉(zhuǎn)換為數(shù)字拋出的異常)
IOException(操作輸入流和輸出流時可能出現(xiàn)的異常)

Java 異常關(guān)鍵字:try日川、catch 、finally 矩乐、throw 龄句、throws

public Test() {
        try {
            int i = 10 / 0;
            System.out.println("i=" + i);
        } catch (ArithmeticException e) {
            //捕獲 ArithmeticException
        } catch (Exception e) {
            //捕獲 Exception
            throw e;
        } finally {
            //do something
        }
    }

    public void test1() throws Exception {
        //do something
    }

1)異常處理機(jī)制

我們都知道除數(shù)不能為0,否則程序就會報錯散罕。像Java中其他對象的創(chuàng)建一樣分歇,使用new在堆上創(chuàng)建異常對象。然后終止當(dāng)前的執(zhí)行路徑欧漱,并且從當(dāng)前環(huán)境中彈出異常對象的引用职抡。此時,異常機(jī)制接管程序误甚,并開始尋找一個恰當(dāng)?shù)牡胤嚼^續(xù)執(zhí)行程序繁调。這個恰當(dāng)?shù)牡胤骄褪钱惓L幚沓绦颍娜蝿?wù)是將程序從錯誤狀態(tài)中恢復(fù)靶草,以使程序能要么換一種方式運(yùn)行,要么繼續(xù)下去岳遥。

2)拋出異常的方式

  • 使用throw拋出異常:throw總是出現(xiàn)在函數(shù)體中奕翔,用來拋出一個Throwable類型的異常。程序會在throw語句后立即終止浩蓉,它后面的語句執(zhí)行不到派继,然后在包含它的所有try塊中(可能在上層調(diào)用函數(shù)中)從里向外尋找含有與其匹配的catch子句的try塊。例如拋出一個IOException類的異常對象:
    throw new IOException ;

  • throws拋出異常:如果一個方法可能會出現(xiàn)異常捻艳,但沒有能力處理這種異常驾窟,可以在方法聲明處用throws子句來聲明拋出異常。throws語句用在方法定義時聲明該方法要拋出的異常類型认轨,如果拋出的是Exception異常類型绅络,則該方法被聲明為拋出所有的異常。多個異常可使用逗號分割恩急。throws語句的語法格式為:methodname throws Exception1,Exception2,..,ExceptionN {} 杉畜。
    當(dāng)方法拋出異常列表的異常時,方法將不對這些類型及其子類類型的異常作處理衷恭,而拋向調(diào)用該方法的方法去處理此叠。

3)重新拋出異常

有時希望把剛捕獲的異常重新拋出,尤其是在使用Exception捕獲所有異常的時候随珠。既然已經(jīng)得到了對當(dāng)前異常的引用灭袁,可以直接把它重新拋出:

catch(Exception e){
    System.out,println("An exception was thrown");
    throw e;
}

重拋異常會把異常拋給上一級環(huán)境中的異常處理程序,同一個try塊的后續(xù)catch子句將被忽略窗看。

注意

  1. 如果是Error茸歧、RuntimeException或它們的子類,那么不可使用throws關(guān)鍵字來聲明要拋出的異常烤芦,雖然編譯可以通過举娩,但是在運(yùn)行時會被系統(tǒng)拋出。

  2. 如果一個方法出現(xiàn)編譯時異常构罗,要么用try-catch語句捕獲铜涉,要么用throws子句聲明將它拋出,否則會導(dǎo)致編譯錯誤遂唧。

  3. 僅當(dāng)拋出了異常芙代,該方法的調(diào)用者才必須處理或者重新拋出該異常。

  4. 調(diào)用方法必須遵循任何可查異常的處理和聲明規(guī)則盖彭。若覆蓋一個方法纹烹,則不能聲明與覆蓋方法不同的異常。聲明的任何異常必須是被覆蓋方法所聲明異常的同類或子類召边。

4)捕獲異常

在Java中铺呵,異常通過try-catch語句捕獲。其一般語法形式為:

try {  
    // 可能會發(fā)生異常的程序代碼  
} catch (Type1 id1){  
    // 捕獲并處置try拋出的異常類型Type1  
}  
catch (Type2 id2){  
     //捕獲并處置try拋出的異常類型Type2  
}  

異常處理程序必須緊跟在try塊之后隧熙。當(dāng)異常被拋出時片挂,異常處理機(jī)制將負(fù)責(zé)搜尋參數(shù)與異常類型想匹配的第一個處理程序。然后進(jìn)入catch子句執(zhí)行贞盯,此時認(rèn)為異常的得到了處理音念。一旦catch子句結(jié)束,則處理程序的查找過程結(jié)束躏敢。只有匹配的catch子句才能得到執(zhí)行闷愤。

可以寫一個異常處理程序來捕獲所有類型的異常。

catch(Exception e){
    System.out.println("Caught an exception");
}

這將捕獲所有異常件余,所以最好把它放在程序列表的末尾讥脐,以防它搶在其他處理程序之前先把異常捕獲了遭居。

因?yàn)镋xception是與編程有關(guān)的所有異常類的基類,所以他不會含有太多具體的信息攘烛,不過可以調(diào)用它從其基類Throwable繼承的方法:

String getMessage()

String getLocalizedMessage()

用來獲取詳細(xì)信息魏滚,或用本地語言表示的詳細(xì)信息。

String toString()

返回對Throwable的簡單描述坟漱,要是有詳細(xì)信息的話鼠次,也會把它包含在內(nèi)。

void printStackTrace()

void printStackTrace(PrintStream)

void printStackTrace(java.io.PrintWriter)

打印Throwable和Throwable的調(diào)用棧軌跡芋齿。其中第一個版本輸出到標(biāo)準(zhǔn)錯誤腥寇,后兩個版本允許選擇輸出的流。
Throwable fillInStackTrace()
用于在Throwable對象的內(nèi)部記錄棧幀的當(dāng)前狀態(tài)觅捆。這在程序重新拋出錯誤或異常時很有用赦役。
此外,也可以使用Throwable從其基類Object繼承的方法栅炒。

5)異常鏈

常常會想要在捕獲一個異常后拋出另一個異常掂摔,并且希望把原始異常的信息保存下來,這被稱為異常鏈∮蓿現(xiàn)在所有Throwable的子類在構(gòu)造器中都可以接受一個cause(因由)對象作為參數(shù)乙漓。這個cause就用來表示原始異常,這樣通過把原始異常傳遞給新的異常释移,使得即使當(dāng)前位置創(chuàng)建并拋出了新的異常叭披,也能通過這個異常鏈追蹤到異常最初發(fā)生的位置。

6)finally

無論是否捕獲或處理異常玩讳,finally塊里的語句都會被執(zhí)行涩蜘,甚至在異常沒有被當(dāng)前的異常處理程序捕獲的情況下,異常處理機(jī)制也會跳到更高一層的異常處理程序之前熏纯,執(zhí)行finally子句同诫,當(dāng)涉及break及continue語句的時候,finally子句也會得到執(zhí)行樟澜。當(dāng)要把除內(nèi)存之外的資源恢復(fù)到它們的初始狀態(tài)時误窖,就要用到finally子句,如已經(jīng)打開的文件或網(wǎng)絡(luò)連接往扔,在屏幕上畫的圖形,甚至可以是外部世界的某個開關(guān)熊户。
當(dāng)在try塊或catch塊中遇到return語句時萍膛,finally語句塊將在方法返回之前被執(zhí)行。在以下4種特殊情況下嚷堡,finally塊不會被執(zhí)行:

  • 在finally語句塊中發(fā)生了異常蝗罗。
  • 在前面的代碼中用了System.exit()退出程序艇棕。
  • 程序所在的線程死亡。
  • 關(guān)閉CPU串塑。

如何自定義異常

public class MyException extends Exception{
    public MyException() {
    }

    public MyException(String message) {
        super(message);
    }

    public MyException(String message, Throwable cause) {
        super(message, cause);
    }

    public MyException(Throwable cause) {
        super(cause);
    }

}

    public void test2() throws MyException {
        //do something
        throw new MyException("");
    }

    public void test3() {
        //do something
        try {
            throw new MyException("");
        } catch (MyException e) {
            e.printStackTrace();
        }
    }

自定義異常通常是定義一個繼承自Exception類的子類沼琉。一般情況下我們都會直接繼承自Exception類,而不會繼承某個運(yùn)行時的異常類桩匪。在程序中使用自定義異常類打瘪,大體可分為以下幾個步驟。

  1. 創(chuàng)建自定義異常:

  2. 在方法中通過throw關(guān)鍵字拋出異常對象:

  3. 如果在當(dāng)前拋出異常的方法中處理異常傻昙,可以使用try-catch語句捕獲并處理闺骚;否則在方法的聲明處通過throws關(guān)鍵字指明要拋出給方法調(diào)用者的異常,繼續(xù)進(jìn)行下一步操作妆档。

  4. 在出現(xiàn)異常方法的調(diào)用者中捕獲并處理異常僻爽。

總結(jié)

Java異常是Java提供的一種識別及響應(yīng)錯誤的一致性機(jī)制。
Java異常機(jī)制可以使程序中異常處理代碼和正常業(yè)務(wù)代碼分離贾惦,降低耦合度胸梆。保證程序代碼更加優(yōu)雅,并提高程序健壯性须板。在有效使用異常的情況下碰镜,異常能清晰的回答what, where, why這3個問題:異常類型回答了“什么”被拋出,異常堆棧跟蹤回答了“在哪“拋出逼纸,異常信息回答了“為什么“會拋出洋措。

Thanks

《Java 編程思想》
http://blog.csdn.net/you_off3/article/details/7572471
https://www.cnblogs.com/skywang12345/p/3544168.html#a2
http://www.importnew.com/1701.html

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市杰刽,隨后出現(xiàn)的幾起案子菠发,更是在濱河造成了極大的恐慌,老刑警劉巖贺嫂,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件滓鸠,死亡現(xiàn)場離奇詭異,居然都是意外死亡第喳,警方通過查閱死者的電腦和手機(jī)糜俗,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來曲饱,“玉大人悠抹,你說我怎么就攤上這事±┑恚” “怎么了楔敌?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長驻谆。 經(jīng)常有香客問我卵凑,道長庆聘,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任勺卢,我火速辦了婚禮伙判,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘黑忱。我一直安慰自己宴抚,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布杨何。 她就那樣靜靜地躺著酱塔,像睡著了一般。 火紅的嫁衣襯著肌膚如雪危虱。 梳的紋絲不亂的頭發(fā)上羊娃,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天,我揣著相機(jī)與錄音埃跷,去河邊找鬼蕊玷。 笑死,一個胖子當(dāng)著我的面吹牛弥雹,可吹牛的內(nèi)容都是我干的垃帅。 我是一名探鬼主播,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼剪勿,長吁一口氣:“原來是場噩夢啊……” “哼贸诚!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起厕吉,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤酱固,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后头朱,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體运悲,經(jīng)...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年项钮,在試婚紗的時候發(fā)現(xiàn)自己被綠了班眯。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 37,997評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡烁巫,死狀恐怖署隘,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情亚隙,我是刑警寧澤磁餐,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布,位于F島的核電站恃鞋,受9級特大地震影響崖媚,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜恤浪,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一畅哑、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧水由,春花似錦荠呐、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至鞠值,卻和暖如春媚创,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背彤恶。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工钞钙, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人声离。 一個月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓芒炼,卻偏偏與公主長得像,于是被迫代替她去往敵國和親术徊。 傳聞我的和親對象是個殘疾皇子本刽,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評論 2 345

推薦閱讀更多精彩內(nèi)容