Java異常處理機(jī)制詳解

初識(shí)異常(Exception)

  • 比如我們?cè)谌?shù)組里面的某個(gè)值得時(shí)候,經(jīng)常會(huì)出現(xiàn)定義的取值范圍超過了數(shù)組的大小,那么運(yùn)行的時(shí)候JVM就會(huì)發(fā)出異常提示。


    BoundException.png
  • 再比如我們要處理的數(shù)據(jù)超出了系統(tǒng)數(shù)據(jù)類型表示范圍時(shí)了罪,由操作系統(tǒng)發(fā)出的Error提示。


    MemoryError.png

發(fā)生異常的原因有很多端仰,但是通常有以下幾大類:輸入了違法的數(shù)據(jù)捶惜、找不到要打開的文件、網(wǎng)絡(luò)通信中斷荔烧、JVM內(nèi)存溢出吱七。

Java異常類層次

Java是通過Throwable類的所有子類來描述各種異常汽久。所有異常的老祖宗都是Throwable。

Throwable.png

Throwable
Throwable 類是所有錯(cuò)誤或異常的超類踊餐。只有當(dāng)對(duì)象是此類(或其子類之一)的實(shí)例時(shí)景醇,才能通過 Java 虛擬機(jī)或者 Java throw 語句拋出。類似地吝岭,只有此類或其子類之一才可以是 catch 中的參數(shù)類型三痰。Throwable類有兩個(gè)重要的子類:Exception(異常)和 Error(錯(cuò)誤)。
Error
Java程序通常不捕獲錯(cuò)誤窜管,出現(xiàn)錯(cuò)誤一般都出現(xiàn)了比較嚴(yán)重的故障散劫,此時(shí)程序已經(jīng)無法處理了,然后在控制臺(tái)通知你幕帆,我已經(jīng)歇菜了获搏。大多數(shù)錯(cuò)誤與程序的執(zhí)行操作無關(guān),而是程序運(yùn)行時(shí)失乾,JVM出了問題常熙,如系統(tǒng)崩潰,虛擬機(jī)錯(cuò)誤碱茁,內(nèi)存空間不足等裸卫。這些錯(cuò)誤,僅靠程序本身無法恢復(fù)和和預(yù)防纽竣,遇到這樣的錯(cuò)誤墓贿,建議讓程序終止。
Exception
Exception類表示程序可以處理的異常蜓氨,是可以捕獲且可能恢復(fù)的募壕。遇到這類異常,應(yīng)該盡可能處理異常语盈,使程序恢復(fù)運(yùn)行,而不應(yīng)該隨意終止異常缰泡。通常刀荒,Java的異常(包括Exception和Error)分為可查的異常(checked exceptions)和不可查的異常(unchecked exceptions)。

可查異常棘钞、不可查異常

  • 可查異常(編譯器要求必須處置的異常):指程序在運(yùn)行中缠借,很容易出現(xiàn)的、情理可容的異常狀況宜猜∑梅担可查異常雖然是異常狀況,但在一定程度上它的發(fā)生是可以預(yù)計(jì)的姨拥,而且一旦發(fā)生這種異常狀況绅喉,就必須采取某種方式進(jìn)行處理渠鸽。
    除了RuntimeException及其子類以外,其他的Exception類及其子類都屬于可查異常柴罐。這種異常的特點(diǎn)是Java編譯器會(huì)檢查它徽缚,也就是說,當(dāng)程序中可能出現(xiàn)這類異常革屠,要么用try-catch語句捕獲它凿试,要么用throws子句聲明拋出它,否則編譯不會(huì)通過似芝。

  • 不可查異常(編譯器不要求強(qiáng)制處置的異常):包括運(yùn)行時(shí)異常(RuntimeException與其子類)和錯(cuò)誤(Error)那婉。
    運(yùn)行時(shí)異常RuntimeException 是可能被程序員避免的異常。它是Exception的一個(gè)重要子類党瓮,是那些可能在 Java 虛擬機(jī)正常運(yùn)行期間拋出的異常的超類详炬。例如:ArithmeticException,一個(gè)整數(shù)“除以零”時(shí)會(huì)拋出此異常麻诀;ArrayStoreException痕寓,試圖將錯(cuò)誤類型的對(duì)象存儲(chǔ)到一個(gè)對(duì)象數(shù)組時(shí)拋出此異常;IndexOutOfBoundsException蝇闭,表示某排序索引(例如對(duì)數(shù)組呻率、字符串排序)超出范圍時(shí)拋出此異常;NullPointerException呻引,當(dāng)應(yīng)用程序試圖在需要對(duì)象的地方使用 null 時(shí)拋出該異常礼仗。這些異常都是不檢查異常,程序中可以選擇捕獲處理逻悠,也可以不處理元践。運(yùn)行時(shí)異常的特點(diǎn)是Java編譯器不會(huì)檢查它,也就是說童谒,當(dāng)程序中可能出現(xiàn)這類異常单旁,即使沒有用try-catch語句捕獲它,也沒有用throws子句聲明拋出它饥伊,也會(huì)編譯通過象浑。

異常方法

下面的列表是 Throwable 類的主要方法:


Method.png

異常處理機(jī)制

在 Java 應(yīng)用程序中,異常處理機(jī)制為:拋出異常琅豆,捕捉異常愉豺。異常總是先被拋出茫因,后被捕捉的蚪拦。

  • 拋出異常:當(dāng)一個(gè)方法出現(xiàn)錯(cuò)誤引發(fā)異常時(shí),方法創(chuàng)建異常對(duì)象并交付運(yùn)行時(shí)系統(tǒng),異常對(duì)象中包含了異常類型和異常出現(xiàn)時(shí)的程序狀態(tài)等異常信息驰贷。運(yùn)行時(shí)系統(tǒng)負(fù)責(zé)尋找處置異常的代碼并執(zhí)行盛嘿。
    注意:
    對(duì)于運(yùn)行時(shí)異常、錯(cuò)誤或可查異常饱苟,Java技術(shù)所要求的異常處理方式有所不同孩擂。
    ① 由于運(yùn)行時(shí)異常的不可查性,為了更合理箱熬、更容易地實(shí)現(xiàn)應(yīng)用程序类垦,Java規(guī)定,運(yùn)行時(shí)異常將由Java運(yùn)行時(shí)系統(tǒng)自動(dòng)拋出城须,允許應(yīng)用程序忽略運(yùn)行時(shí)異常蚤认。對(duì)于方法運(yùn)行中可能出現(xiàn)的Error猖辫,當(dāng)運(yùn)行方法不欲捕捉時(shí)蚜迅,Java允許該方法不做任何拋出聲明度秘。因?yàn)楣兀蠖鄶?shù)Error異常屬于永遠(yuǎn)不能被允許發(fā)生的狀況,也屬于合理的應(yīng)用程序不該捕捉的異常瘫想。
    ② 對(duì)于所有的可查異常昧谊,Java規(guī)定:一個(gè)方法必須捕捉玫霎,或者聲明拋出方法之外褥蚯。也就是說挚冤,當(dāng)一個(gè)方法選擇不捕捉可查異常時(shí),它必須聲明將拋出異常赞庶。
    代碼示例
    ① throws語句用在方法定義時(shí)聲明該方法要拋出的異常類型训挡,如果拋出的是Exception異常類型,則該方法被聲明為拋出所有的異常歧强。
    ② 當(dāng)方法拋出異常列表的異常時(shí)澜薄,方法將不對(duì)這些類型及其子類類型的異常作處理,而拋向調(diào)用該方法的方法摊册,如果調(diào)用者不想處理該異常肤京,可以繼續(xù)向上拋出,但最終要有能夠處理該異常的調(diào)用者茅特。
    ③ throw總是出現(xiàn)在函數(shù)體中蟆沫,用來拋出一個(gè)Throwable類型的異常。程序會(huì)在throw語句后立即終止温治,它后面的語句執(zhí)行不到。
public class ClassName
{
  public void named(String string) throws RemoteException
  {
    // Method implementation
    throw new RemoteException();
  }
  //Remainder of class definition
}

一個(gè)方法可以聲明拋出多個(gè)異常戒悠,多個(gè)異常之間用逗號(hào)隔開熬荆。

public class ClassName
{
   public void withdraw(double amount) throws RemoteException, InsufficientFundsException
   {
       // Method implementation
   }
   //Remainder of class definition
}
  • 捕獲異常:使用 try 和 catch 關(guān)鍵字可以捕獲異常。try/catch 代碼塊放在異吵窈可能發(fā)生的地方卤恳。
    語法
try
{
   // 程序代碼
}catch(ExceptionName e)
{
   //Catch 塊
}

當(dāng)try內(nèi)的監(jiān)控區(qū)域發(fā)生異常累盗,就會(huì)匹配后面的catch塊。Java方法在運(yùn)行過程中出現(xiàn)異常突琳,則創(chuàng)建異常對(duì)象若债。將異常拋出監(jiān)控區(qū)域之外,由Java運(yùn)行時(shí)系統(tǒng)試圖尋找匹配的catch子句以捕獲異常拆融。若有匹配的catch子句蠢琳,則運(yùn)行其異常處理代碼,try-catch語句結(jié)束镜豹。
匹配的原則是:如果拋出的異常對(duì)象屬于catch塊的異常類傲须,或者屬于該異常類的子類,則認(rèn)為生成的異常對(duì)象與catch塊捕獲的異常類型相匹配趟脂。
try/catch 實(shí)例:

public class Test{

    public static void main(String args[]){
        try{
            int a[] = new int[2];
            System.out.println("輸出數(shù)組 :" + a[3]);
        }catch(ArrayIndexOutOfBoundsException e){
            System.out.println("拋出異常  :" + e);
        }
    }
}

多重捕獲塊:

try{
   // 程序代碼
}catch(異常類型1 異常的變量名1){
  // 程序代碼
}catch(異常類型2 異常的變量名2){
  // 程序代碼
}catch(異常類型2 異常的變量名2){
  // 程序代碼
}

如果監(jiān)控區(qū)域發(fā)生異常泰讽,異常被拋給第一個(gè) catch 塊。如果拋出異常的數(shù)據(jù)類型與 ExceptionType1 匹配昔期,它在這里就會(huì)被捕獲已卸。如果不匹配,它會(huì)被傳遞給第二個(gè) catch 塊硼一。如此累澡,直到異常被捕獲或者通過所有的 catch 塊。
多重捕獲塊實(shí)例:

public class TestException {  
    public static void main(String[] args) {  
        int[] intArray = new int[3];  
        try {  
            for (int i = 0; i <= intArray.length; i++) {  
                intArray[i] = i;  
                System.out.println("intArray[" + i + "] = " + intArray[i]);  
                System.out.println("intArray[" + i + "]模 " + (i - 2) + "的值:  "  
                        + intArray[i] % (i - 2));  
            }  
        } catch (ArrayIndexOutOfBoundsException e) {  
            System.out.println("intArray數(shù)組下標(biāo)越界異常欠动。");  
        } catch (ArithmeticException e) {  
            System.out.println("除數(shù)為0異常永乌。");  
        }  
        System.out.println("程序正常結(jié)束。");  
    }  
} 
//intArray[0] = 0
//intArray[0]模 -2的值:  0
//intArray[1] = 1
//intArray[1]模 -1的值:  0
//intArray[2] = 2
//除數(shù)為0異常具伍。
//程序正常結(jié)束翅雏。

注意:一旦某個(gè)catch捕獲到匹配的異常類型,將進(jìn)入異常處理代碼人芽。一經(jīng)處理結(jié)束望几,就意味著整個(gè)try-catch語句結(jié)束。其他的catch子句不再有匹配和捕獲異常類型的機(jī)會(huì)萤厅。
finally關(guān)鍵字
① 無論是否發(fā)生異常橄抹,finally 代碼塊中的代碼總會(huì)被執(zhí)行。
② 在 finally 代碼塊中惕味,可以運(yùn)行清理類型等收尾善后性質(zhì)的語句楼誓。
③ finally 代碼塊出現(xiàn)在 catch 代碼塊最后。
④ finally中使用return是一種很不好的編程風(fēng)格名挥,它會(huì)覆蓋掉所有的其它返回疟羹,并且吃掉catch中拋出的異常。
語法如下:

try{
  // 程序代碼
}catch(異常類型1 異常的變量名1){
  // 程序代碼
}catch(異常類型2 異常的變量名2){
  // 程序代碼
}finally{
  // 程序代碼
}

代碼實(shí)例:

public class ExcepTest{
  public static void main(String args[]){
    int a[] = new int[2];
    try{
       System.out.println("Access element three :" + a[3]);
    }catch(ArrayIndexOutOfBoundsException e){
       System.out.println("Exception thrown  :" + e);
    }
    finally{
       a[0] = 6;
       System.out.println("First element value: " +a[0]);
       System.out.println("The finally statement is executed");
    }
  }
}
//Exception thrown  :java.lang.ArrayIndexOutOfBoundsException: 3
//First element value: 6
//The finally statement is executed

注意:當(dāng)在try塊或catch塊中遇到return語句時(shí),finally語句塊將在方法返回之前被執(zhí)行榄融。在finally語句塊中發(fā)生了異常参淫,finally塊不會(huì)被執(zhí)行。
try-catch-finally執(zhí)行順序
1)當(dāng)try沒有捕獲到異常時(shí):try語句塊中的語句逐一被執(zhí)行愧杯,程序?qū)⑻^catch語句塊涎才,執(zhí)行finally語句塊和其后的語句;
2)當(dāng)try捕獲到異常力九,catch語句塊里沒有處理此異常的情況:當(dāng)try語句塊里的某條語句出現(xiàn)異常時(shí)耍铜,而沒有處理此異常的catch語句塊時(shí),此異常將會(huì)拋給JVM處理畏邢,finally語句塊里的語句還是會(huì)被執(zhí)行业扒,但finally語句塊后的語句不會(huì)被執(zhí)行;
3)當(dāng)try捕獲到異常舒萎,catch語句塊里有處理此異常的情況:在try語句塊中是按照順序來執(zhí)行的程储,當(dāng)執(zhí)行到某一條語句出現(xiàn)異常時(shí),程序?qū)⑻絚atch語句塊臂寝,并與catch語句塊逐一匹配章鲤,找到與之對(duì)應(yīng)的處理程序,其他的catch語句塊將不會(huì)被執(zhí)行咆贬,而try語句塊中败徊,出現(xiàn)異常之后的語句也不會(huì)被執(zhí)行,catch語句塊執(zhí)行完后掏缎,執(zhí)行finally語句塊里的語句皱蹦,最后執(zhí)行finally語句塊后的語句;

自定義異常

import java.lang.Exception;  
public class TestException {  
    static int quotient(int x, int y) throws MyException { // 定義方法拋出異常  
        if (y < 0) { // 判斷參數(shù)是否小于0  
            throw new MyException("除數(shù)不能是負(fù)數(shù)"); // 異常信息  
        }  
        return x/y; // 返回值  
    }  
    public static void main(String args[]) { // 主方法  
        int  a =3;  
        int  b =0;   
        try { // try語句包含可能發(fā)生異常的語句  
            int result = quotient(a, b); // 調(diào)用方法quotient()  
        } catch (MyException e) { // 處理自定義異常  
            System.out.println(e.getMessage()); // 輸出異常信息  
        } catch (ArithmeticException e) { // 處理ArithmeticException異常  
            System.out.println("除數(shù)不能為0"); // 輸出提示信息  
        } catch (Exception e) { // 處理其他異常  
            System.out.println("程序發(fā)生了其他的異常"); // 輸出提示信息  
        }  
    }  
  
}  
class MyException extends Exception { // 創(chuàng)建自定義異常類  
    String message; // 定義String類型變量  
    public MyException(String ErrorMessagr) { // 父類方法  
        message = ErrorMessagr;  
    }  
  
    public String getMessage() { // 覆蓋getMessage()方法  
        return message;  
    }  
}

注意
子類重寫父類的方法的時(shí)候眷蜈,如果父類沒有異常沪哺,那么子類也不允許在重寫的方法拋出異常有異常。也就是說父類沒有拋出異常酌儒,那么子類也不可以辜妓。

寫完嘍!ㄟ(▔,▔)ㄏㄟ(▔,▔)ㄏㄟ(▔,▔)ㄏ


知識(shí)重在總結(jié)和梳理忌怎,只有不斷地去學(xué)習(xí)并運(yùn)用籍滴,才能化為自己的東西。當(dāng)你能為別人講明白的時(shí)候榴啸,說明自己已經(jīng)掌握了孽惰。

歡迎轉(zhuǎn)載,轉(zhuǎn)載請(qǐng)注明出處鸥印!

如果有錯(cuò)誤的地方勋功,或者有您的見解腥例,還請(qǐng)不嗇賜教!

喜歡的話酝润,麻煩點(diǎn)個(gè)贊!

本文轉(zhuǎn)載自:http://blog.csdn.net/hguisu/article/details/6155636

l

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末璃弄,一起剝皮案震驚了整個(gè)濱河市要销,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌夏块,老刑警劉巖疏咐,帶你破解...
    沈念sama閱讀 206,839評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異脐供,居然都是意外死亡浑塞,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門政己,熙熙樓的掌柜王于貴愁眉苦臉地迎上來酌壕,“玉大人,你說我怎么就攤上這事歇由÷央梗” “怎么了?”我有些...
    開封第一講書人閱讀 153,116評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵沦泌,是天一觀的道長(zhǎng)糊昙。 經(jīng)常有香客問我,道長(zhǎng)谢谦,這世上最難降的妖魔是什么释牺? 我笑而不...
    開封第一講書人閱讀 55,371評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮回挽,結(jié)果婚禮上没咙,老公的妹妹穿的比我還像新娘。我一直安慰自己厅各,他們只是感情好镜撩,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評(píng)論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著队塘,像睡著了一般袁梗。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上憔古,一...
    開封第一講書人閱讀 49,111評(píng)論 1 285
  • 那天遮怜,我揣著相機(jī)與錄音,去河邊找鬼鸿市。 笑死锯梁,一個(gè)胖子當(dāng)著我的面吹牛即碗,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播陌凳,決...
    沈念sama閱讀 38,416評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼剥懒,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了合敦?” 一聲冷哼從身側(cè)響起初橘,我...
    開封第一講書人閱讀 37,053評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎充岛,沒想到半個(gè)月后保檐,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,558評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡崔梗,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評(píng)論 2 325
  • 正文 我和宋清朗相戀三年夜只,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蒜魄。...
    茶點(diǎn)故事閱讀 38,117評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡扔亥,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出权悟,到底是詐尸還是另有隱情砸王,我是刑警寧澤,帶...
    沈念sama閱讀 33,756評(píng)論 4 324
  • 正文 年R本政府宣布峦阁,位于F島的核電站谦铃,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏榔昔。R本人自食惡果不足惜驹闰,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望撒会。 院中可真熱鬧嘹朗,春花似錦、人聲如沸诵肛。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)怔檩。三九已至褪秀,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間薛训,已是汗流浹背媒吗。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留乙埃,地道東北人闸英。 一個(gè)月前我還...
    沈念sama閱讀 45,578評(píng)論 2 355
  • 正文 我出身青樓锯岖,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親甫何。 傳聞我的和親對(duì)象是個(gè)殘疾皇子出吹,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評(píng)論 2 345

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