理解JAVA異常

異常

1. Throwable: 有兩個(gè)重要的子類:Exception(異常)和Error(錯(cuò)誤)

2. Error: 程序無法處理的錯(cuò)誤捂齐。大多數(shù)錯(cuò)誤與代碼編寫者執(zhí)行的操作無關(guān)确徙,而表示代碼運(yùn)行時(shí)JVM出現(xiàn)的問題,例如乎莉,Java虛擬機(jī)運(yùn)行錯(cuò)誤(Virtual MachineError)愚屁,當(dāng) JVM 不再有繼續(xù)執(zhí)行操作所需的內(nèi)存資源時(shí),將出現(xiàn) OutOfMemoryError絮重。這些異常發(fā)生時(shí)冤寿,Java虛擬機(jī)(JVM)一般會(huì)選擇線程終止。

3. Exception: 是程序本身可以處理的異常

  • RuntimeException
    表示JVM常用操作引發(fā)的錯(cuò)誤青伤,例如督怜,若試圖使用空值對(duì)象引用、除數(shù)為零或數(shù)組越界狠角,則分別引發(fā)運(yùn)行時(shí)異常(NullPointerException号杠、ArithmeticException)和 ArrayIndexOutOfBoundException。

     注意:異常和錯(cuò)誤的區(qū)別:異常能被程序本身可以處理丰歌,錯(cuò)誤是無法處理姨蟋。
    
  • JAVA異常(包括Exception和Error)分為可查的異常(checked exceptions)和不可查的異常(unchecked exceptions)。

    1. 可查異常
      除了RuntimeException及其子類以外动遭,其他的Exception類及其子類都屬于可查異常芬探。要么用try-catch語句捕獲它,要么用throws子句聲明拋出它厘惦,否則編譯不會(huì)通過偷仿。

    2. 不可查異常:包括運(yùn)行時(shí)異常(RuntimeException與其子類)和錯(cuò)誤(Error)。

  • Exception 這種異常分兩大類運(yùn)行時(shí)異常和非運(yùn)行時(shí)異常(編譯異常)宵蕉。

    1. 運(yùn)行時(shí)異常
      RuntimeException類及其子類異常酝静,如NullPointerException(空指針異常)、IndexOutOfBoundsException(下標(biāo)越界異常)等羡玛,這些異常是不檢查異常别智,程序中可以選擇捕獲處理,也可以不處理稼稿。

      運(yùn)行時(shí)異常特點(diǎn):Java編譯器不會(huì)檢查它薄榛,也就是說,當(dāng)程序中可能出現(xiàn)這類異常让歼,即使沒有用try-catch語句捕獲它敞恋,也沒有用throws子句聲明拋出它,也會(huì)編譯通過谋右。

    2. 非運(yùn)行時(shí)異常(編譯異常)
      是RuntimeException以外的異常硬猫,類型上都屬于Exception類及其子類。必須進(jìn)行處理的異常,如果不處理啸蜜,程序就不能編譯通過坑雅。如IOException、SQLException等以及用戶自定義的Exception異常



異常處理機(jī)制

總體來說:對(duì)于可查異常必須捕捉衬横、或者聲明拋出裹粤。允許忽略不可查的 RuntimeException 和 Error。
捕獲異常:try冕香、catch 和 finally

1. try-catch語句

語法:

try {  
    // 可能會(huì)發(fā)生異常的程序代碼  
} catch (Type1 id1){  
    // 捕獲并處置try拋出的異常類型Type1  
}  
catch (Type2 id2){  
     //捕獲并處置try拋出的異常類型Type2  
}  
  • try后為監(jiān)控區(qū)域蛹尝。若出現(xiàn)異常,則創(chuàng)建異常對(duì)象悉尾,將對(duì)象拋出監(jiān)控區(qū)域之外并尋找匹配的catch子句捕獲異常。
    匹配原則:若拋出對(duì)象屬于catch句子的異常類或子類挫酿,則匹配

  • 例1 “除數(shù)為0”引發(fā)的ArithmeticException異常构眯。

 public static void main(String[] args) {  
        int a = 6;  
        int b = 0;  
        try {  
            System.out.println("a/b的值是:" + a / b);  
        } catch (ArithmeticException e) {  
            System.out.println("程序出現(xiàn)異常,變量b不能為0早龟。");  
        }  
        System.out.println("程序正常結(jié)束惫霸。");  
    }  
}  
結(jié)果:
程序出現(xiàn)異常,變量b不能為0葱弟。
程序正常結(jié)束壹店。
  • 在該例中,b=0引發(fā)ArithmeticException異常芝加,運(yùn)行時(shí)系統(tǒng)創(chuàng)建異常對(duì)象并拋出監(jiān)控區(qū)域硅卢,轉(zhuǎn)而匹配合適的異常處理器catch,并執(zhí)行相應(yīng)的異常處理代碼藏杖。
    事實(shí)上将塑,ArithmeticException異常屬于運(yùn)行時(shí)異常,由于檢查運(yùn)行時(shí)異常的代價(jià)遠(yuǎn)大于捕捉異常所帶來的益處蝌麸,所以一般不做處理

  • 例2 存在除數(shù)為0和下標(biāo)越界異常

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é)束来吩。");  
    }  
}  
結(jié)果:
intArray[0] = 0
intArray[0]模 -2的值:  0
intArray[1] = 1
intArray[1]模 -1的值:  0
intArray[2] = 2
除數(shù)為0異常敢辩。
程序正常結(jié)束。
  • 在該例中弟疆,可能會(huì)出現(xiàn)下標(biāo)越界和除數(shù)為0兩種異常戚长,但除數(shù)為0先匹配,因此執(zhí)行相應(yīng)的catch語句

    注意:一旦某個(gè)catch捕獲到匹配的異常類型兽间,將進(jìn)入異常處理代碼历葛。一經(jīng)處理結(jié)束,就意味著整個(gè)try-catch語句結(jié)束。其他的catch子句不再有匹配和捕獲異常類型的機(jī)會(huì)
    

2. try-catch-finally 語句

語法:

try {  
    // 可能會(huì)發(fā)生異常的程序代碼  
} catch (Type1 id1) {  
    // 捕獲并處理try拋出的異常類型Type1  
} catch (Type2 id2) {  
    // 捕獲并處理try拋出的異常類型Type2  
} finally {  
    // 無論是否發(fā)生異常恤溶,都將執(zhí)行的語句塊  
} 
  • 例1 帶finally子句的異常處理程序乓诽。
public class TestException {  
    public static void main(String args[]) {  
        int i = 0;  
        String greetings[] = { " Hello world !", " Hello World !! "};  
        while (i < 3) {  
            try {  
                // 特別注意循環(huán)控制變量i的設(shè)計(jì),避免造成無限循環(huán)  
                System.out.println(greetings[i++]);  
            } catch (ArrayIndexOutOfBoundsException e) {  
                System.out.println("數(shù)組下標(biāo)越界異常");  
            } finally {  
                System.out.println("--------------------------");  
            }  
        }  
    }  
} 
運(yùn)行結(jié)果:
Hello world !
--------------------------
Hello World !!
--------------------------
數(shù)組下標(biāo)越界異常
--------------------------
  • 特別注意try子句中語句塊的設(shè)計(jì)咒程,如果設(shè)計(jì)為如下鸠天,將會(huì)出現(xiàn)死循環(huán)。
try {  System.out.println (greetings[i]); i++;  } 

小結(jié):
try 塊:用于捕獲異常帐姻。其后可接零個(gè)或多個(gè)catch塊稠集,如果沒有catch塊,則必須跟一個(gè)finally塊饥瓷。
catch 塊:用于處理try捕獲到的異常剥纷。
finally 塊:無論是否捕獲或處理異常,finally塊里的語句都會(huì)被執(zhí)行呢铆。當(dāng)在try塊或catch塊中遇到return語句時(shí)晦鞋,finally語句塊將在方法返回之前被執(zhí)行。在以下4種特殊情況下棺克,finally塊不會(huì)被執(zhí)行:
1)在finally語句塊中發(fā)生了異常悠垛。
2)在前面的代碼中用了System.exit()退出程序。
3)程序所在的線程死亡娜谊。
4)關(guān)閉CPU确买。

3. try、catch纱皆、finally語句塊的執(zhí)行順序

1)try中沒有異常:try中順序執(zhí)行湾趾,跳過catch語句,執(zhí)行finally語句和后面的語句
2)try捕獲異常抹剩,沒有catch匹配異常:該異常會(huì)拋給JVM處理撑帖,finally語句塊還是會(huì)執(zhí)行,但后面的語句不會(huì)執(zhí)行
3)try捕獲異常澳眷,有catch匹配并處理:出現(xiàn)異常胡嘿,程序跳到相應(yīng)的catch語句塊,其他catch不會(huì)執(zhí)行钳踊,try語句塊中衷敌,出現(xiàn)異常之后的語句也不會(huì)被執(zhí)行,catch執(zhí)行完之后執(zhí)行finally語句塊拓瞪,最后執(zhí)行后面的語句

拋出異常

1. throws拋出異常
語法:

methodname throws Exception1,Exception2,...
{  
}  
  • throws語句在定義方法時(shí)聲明要拋出的異常類型缴罗,多個(gè)異常可以用逗號(hào)分隔祭埂。當(dāng)方法拋出異常時(shí)面氓,該方法不對(duì)這些類型的異常以及子類進(jìn)行處理兵钮,而是拋向調(diào)用該方法的方法。例如:
import java.lang.Exception;  
public class Test {  

    static void pop() throws NegativeArraySizeException {  
        // 定義方法并拋出NegativeArraySizeException異常  
        int[] arr = new int[-3]; // 創(chuàng)建數(shù)組  
    }  
  
    public static void main(String[] args) { // 主方法  
        try { // try語句處理異常信息  
            pop(); // 調(diào)用pop()方法  
        } catch (NegativeArraySizeException e) {  
            System.out.println("pop()方法拋出的異常");// 輸出異常信息  
        }  
    }  
  
}  
  • 使用throws關(guān)鍵字將異常拋給調(diào)用者后舌界,如果調(diào)用者不想處理該異常掘譬,可以繼續(xù)向上拋出,但最終要有能夠處理該異常的調(diào)用者呻拌。
    pop方法沒有處理異常NegativeArraySizeException葱轩,而是由main函數(shù)來處理。

  • throws拋出異常規(guī)則
    1)不可查異常(Error藐握,RuntimeException)靴拱,可以不拋出,編譯時(shí)會(huì)通過猾普,運(yùn)行時(shí)被系統(tǒng)拋出
    2)可查異常袜炕,要么拋出,要么捕獲
    3)當(dāng)拋出異常抬闷,該方法的調(diào)用者必須處理或者重新拋出
    4)若聲明一個(gè)異常妇蛀,則不能聲明與覆蓋方法不同的異常。聲明的任何異常必須是被覆蓋方法所聲明異常的同類或子類笤成。
    例如:

void method1() throws IOException{}  //合法    
   
//編譯錯(cuò)誤,必須捕獲或聲明拋出IOException    
void method2(){    
  method1();    
}    
   
//合法眷茁,聲明拋出IOException    
void method3()throws IOException {    
  method1();    
}    
   
//合法炕泳,聲明拋出Exception,IOException是Exception的子類    
void method4()throws Exception {    
  method1();    
}    
   
//合法上祈,捕獲IOException    
void method5(){    
 try{    
    method1();    
 }catch(IOException e){…}    
}    
   
//編譯錯(cuò)誤培遵,必須捕獲或聲明拋出Exception    
void method6(){    
  try{    
    method1();    
  }catch(IOException e){throw new Exception();}    
}    
   
//合法,聲明拋出Exception    
void method7()throws Exception{    
 try{    
  method1();    
 }catch(IOException e){throw new Exception();}    
}

2. 使用throws

  • throw用來拋出一個(gè)Throwable類型的異常登刺。程序會(huì)在throw語句后立即終止籽腕,它后面的語句執(zhí)行不到,然后在包含它的所有try塊中(可能在上層調(diào)用函數(shù)中)從里向外尋找含有與其匹配的catch子句的try塊纸俭。

  • 異常是異常類的實(shí)例對(duì)象皇耗,我們可以創(chuàng)建異常類的實(shí)例對(duì)象通過throw語句拋出。該語句的語法格式為:

    throw new exceptionname;
    

    例如拋出一個(gè)IOException類的異常對(duì)象:

     throw new IOException;
    
  • 注意的是揍很,throw 拋出的只能夠是Throwable類 或者其子類的實(shí)例對(duì)象郎楼。下面的操作是錯(cuò)誤的:

    throw new String("exception");
    
  • 如果拋出了檢查異常,則還應(yīng)該在方法頭部聲明方法可能拋出的異常類型窒悔。該方法的調(diào)用者也必須檢查處理拋出的異常呜袁。

  • 如果所有方法都層層上拋獲取的異常,最終JVM會(huì)進(jìn)行處理简珠,處理也很簡(jiǎn)單阶界,就是打印異常消息和堆棧信息。如果拋出的是Error或RuntimeException,則該方法的調(diào)用者可選擇處理該異常膘融。

package Test;  
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;  
    }  
} 


JAVA常見異常

1. runtimeException子類

  • java.lang.ArrayIndexOutOfBoundsException
    數(shù)組索引越界異常芙粱。當(dāng)對(duì)數(shù)組的索引值為負(fù)數(shù)或大于等于數(shù)組大小時(shí)拋出。

  • java.lang.ArithmeticException
    算術(shù)條件異常托启。譬如:整數(shù)除零等宅倒。

  • java.lang.NullPointerException
    空指針異常。當(dāng)應(yīng)用試圖在要求使用對(duì)象的地方使用了null時(shí)屯耸,拋出該異常拐迁。譬如:調(diào)用null對(duì)象的實(shí)例方法、訪問null對(duì)象的屬性疗绣、計(jì)算null對(duì)象的長(zhǎng)度线召、使用throw語句拋出null等等

  • java.lang.ClassNotFoundException
    找不到類異常。當(dāng)應(yīng)用試圖根據(jù)字符串形式的類名構(gòu)造類多矮,而在遍歷CLASSPAH之后找不到對(duì)應(yīng)名稱的class文件時(shí)缓淹,拋出該異常。

  • java.lang.NegativeArraySizeException
    數(shù)組長(zhǎng)度為負(fù)異常

  • java.lang.ArrayStoreException
    數(shù)組中包含不兼容的值拋出的異常

  • java.lang.SecurityException
    安全性異常

  • java.lang.IllegalArgumentException
    非法參數(shù)異常

2. IoException子類

  • IOException:操作輸入流和輸出流時(shí)可能出現(xiàn)的異常塔逃。
  • EOFException 文件已結(jié)束異常
  • FileNotFoundException 文件未找到異常
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末讯壶,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子湾盗,更是在濱河造成了極大的恐慌伏蚊,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件格粪,死亡現(xiàn)場(chǎng)離奇詭異躏吊,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)帐萎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門比伏,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人疆导,你說我怎么就攤上這事赁项。” “怎么了是鬼?”我有些...
    開封第一講書人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵肤舞,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我均蜜,道長(zhǎng)李剖,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任囤耳,我火速辦了婚禮篙顺,結(jié)果婚禮上偶芍,老公的妹妹穿的比我還像新娘。我一直安慰自己德玫,他們只是感情好匪蟀,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著宰僧,像睡著了一般材彪。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上琴儿,一...
    開封第一講書人閱讀 49,007評(píng)論 1 284
  • 那天段化,我揣著相機(jī)與錄音,去河邊找鬼造成。 笑死显熏,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的晒屎。 我是一名探鬼主播喘蟆,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼鼓鲁!你這毒婦竟也來了蕴轨?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤骇吭,失蹤者是張志新(化名)和其女友劉穎尺棋,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體绵跷,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年成福,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了碾局。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡奴艾,死狀恐怖净当,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情蕴潦,我是刑警寧澤像啼,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布,位于F島的核電站潭苞,受9級(jí)特大地震影響忽冻,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜此疹,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一僧诚、第九天 我趴在偏房一處隱蔽的房頂上張望遮婶。 院中可真熱鬧,春花似錦湖笨、人聲如沸旗扑。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽臀防。三九已至,卻和暖如春边败,著一層夾襖步出監(jiān)牢的瞬間袱衷,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來泰國(guó)打工放闺, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留祟昭,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓怖侦,卻偏偏與公主長(zhǎng)得像篡悟,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子匾寝,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345

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

  • 八搬葬、深入理解java異常處理機(jī)制 引子try…catch…finally恐怕是大家再熟悉不過的語句了, 你的答案是...
    壹點(diǎn)零閱讀 1,530評(píng)論 0 0
  • 引言 在程序運(yùn)行過程中(注意是運(yùn)行階段艳悔,程序可以通過編譯)急凰,如果JVM檢測(cè)出一個(gè)不可能執(zhí)行的操作,就會(huì)出現(xiàn)運(yùn)行時(shí)錯(cuò)...
    Steven1997閱讀 2,401評(píng)論 1 6
  • 在理想狀態(tài)下猜年,程序會(huì)按照我們預(yù)想的步驟一步一步的執(zhí)行抡锈,但是即使你是大牛,你也不可避免出錯(cuò)乔外,所以java為我們提供了...
    Single_YAM閱讀 4,249評(píng)論 1 18
  • 好不容易的假期床三,這應(yīng)該是我第一次帶著小孩子出來玩吧,兒子對(duì)我的評(píng)價(jià)是“媽媽一面是魔鬼杨幼,一面是天使” 我呵呵一笑撇簿,每...
    冬元的回憶閱讀 245評(píng)論 0 1
  • 作為一名寫手,自然都希望自己的文閱讀量上萬差购,點(diǎn)贊評(píng)論打賞不斷四瘫,不但證明了自己的寫文能力,更能一種成就感欲逃,最好還能忙...
    君悅?cè)?/span>閱讀 6,534評(píng)論 40 44