理解JAVA異常

異常

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

2. Error: 程序無(wú)法處理的錯(cuò)誤。大多數(shù)錯(cuò)誤與代碼編寫(xiě)者執(zhí)行的操作無(wú)關(guān),而表示代碼運(yùn)行時(shí)JVM出現(xiàn)的問(wè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ò)誤是無(wú)法處理。
    
  • JAVA異常(包括Exception和Error)分為可查的異常(checked exceptions)和不可查的異常(unchecked exceptions)。

    1. 可查異常
      除了RuntimeException及其子類(lèi)以外,其他的Exception類(lèi)及其子類(lèi)都屬于可查異常。要么用try-catch語(yǔ)句捕獲它,要么用throws子句聲明拋出它,否則編譯不會(huì)通過(guò)。

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

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

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

      運(yùn)行時(shí)異常特點(diǎn):Java編譯器不會(huì)檢查它,也就是說(shuō),當(dāng)程序中可能出現(xiàn)這類(lèi)異常,即使沒(méi)有用try-catch語(yǔ)句捕獲它,也沒(méi)有用throws子句聲明拋出它,也會(huì)編譯通過(guò)。

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



異常處理機(jī)制

總體來(lái)說(shuō):對(duì)于可查異常必須捕捉、或者聲明拋出。允許忽略不可查的 RuntimeException 和 Error。
捕獲異常:try、catch 和 finally

1. try-catch語(yǔ)句

語(yǔ)法:

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

  • 例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)大于捕捉異常所帶來(lái)的益處,所以一般不做處理

  • 例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語(yǔ)句

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

2. try-catch-finally 語(yǔ)句

語(yǔ)法:

try {  
    // 可能會(huì)發(fā)生異常的程序代碼  
} catch (Type1 id1) {  
    // 捕獲并處理try拋出的異常類(lèi)型Type1  
} catch (Type2 id2) {  
    // 捕獲并處理try拋出的異常類(lèi)型Type2  
} finally {  
    // 無(wú)論是否發(fā)生異常,都將執(zhí)行的語(yǔ)句塊  
} 
  • 例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ì),避免造成無(wú)限循環(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子句中語(yǔ)句塊的設(shè)計(jì),如果設(shè)計(jì)為如下,將會(huì)出現(xiàn)死循環(huán)。
try {  System.out.println (greetings[i]); i++;  } 

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

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

1)try中沒(méi)有異常:try中順序執(zhí)行,跳過(guò)catch語(yǔ)句,執(zhí)行finally語(yǔ)句和后面的語(yǔ)句
2)try捕獲異常,沒(méi)有catch匹配異常:該異常會(huì)拋給JVM處理,finally語(yǔ)句塊還是會(huì)執(zhí)行,但后面的語(yǔ)句不會(huì)執(zhí)行
3)try捕獲異常,有catch匹配并處理:出現(xiàn)異常,程序跳到相應(yīng)的catch語(yǔ)句塊,其他catch不會(huì)執(zhí)行,try語(yǔ)句塊中,出現(xiàn)異常之后的語(yǔ)句也不會(huì)被執(zhí)行,catch執(zhí)行完之后執(zhí)行finally語(yǔ)句塊,最后執(zhí)行后面的語(yǔ)句

拋出異常

1. throws拋出異常
語(yǔ)法:

methodname throws Exception1,Exception2,...
{  
}  
  • throws語(yǔ)句在定義方法時(shí)聲明要拋出的異常類(lèi)型,多個(gè)異??梢杂枚禾?hào)分隔。當(dāng)方法拋出異常時(shí),該方法不對(duì)這些類(lèi)型的異常以及子類(lèi)進(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語(yǔ)句處理異常信息  
            pop(); // 調(diào)用pop()方法  
        } catch (NegativeArraySizeException e) {  
            System.out.println("pop()方法拋出的異常");// 輸出異常信息  
        }  
    }  
  
}  
  • 使用throws關(guān)鍵字將異常拋給調(diào)用者后,如果調(diào)用者不想處理該異常,可以繼續(xù)向上拋出,但最終要有能夠處理該異常的調(diào)用者。
    pop方法沒(méi)有處理異常NegativeArraySizeException,而是由main函數(shù)來(lái)處理。

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

void method1() throws IOException{}  //合法    
   
//編譯錯(cuò)誤,必須捕獲或聲明拋出IOException    
void method2(){    
  method1();    
}    
   
//合法,聲明拋出IOException    
void method3()throws IOException {    
  method1();    
}    
   
//合法,聲明拋出Exception,IOException是Exception的子類(lèi)    
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用來(lái)拋出一個(gè)Throwable類(lèi)型的異常。程序會(huì)在throw語(yǔ)句后立即終止,它后面的語(yǔ)句執(zhí)行不到,然后在包含它的所有try塊中(可能在上層調(diào)用函數(shù)中)從里向外尋找含有與其匹配的catch子句的try塊。

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

    throw new exceptionname;
    

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

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

    throw new String("exception");
    
  • 如果拋出了檢查異常,則還應(yīng)該在方法頭部聲明方法可能拋出的異常類(lèi)型。該方法的調(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語(yǔ)句包含可能發(fā)生異常的語(yǔ)句  
            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)建自定義異常類(lèi)  
    String message; // 定義String類(lèi)型變量  
    public MyException(String ErrorMessagr) { // 父類(lèi)方法  
        message = ErrorMessagr;  
    }  
  
    public String getMessage() { // 覆蓋getMessage()方法  
        return message;  
    }  
} 


JAVA常見(jiàn)異常

1. runtimeException子類(lèi)

  • 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í)例方法、訪問(wèn)null對(duì)象的屬性、計(jì)算null對(duì)象的長(zhǎng)度、使用throw語(yǔ)句拋出null等等

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

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

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

  • java.lang.SecurityException
    安全性異常

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

2. IoException子類(lèi)

  • IOException:操作輸入流和輸出流時(shí)可能出現(xiàn)的異常。
  • EOFException 文件已結(jié)束異常
  • FileNotFoundException 文件未找到異常
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

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

友情鏈接更多精彩內(nèi)容