Java面向對象之異常【一】

Java面向對象之異常【一】

終於完成本學期的最後一門考試,考試周的我,邊複習通訊之傅里葉變換,邊學習Java的新知識。雖然好久沒更,可是私底下的筆記滿滿,特意總結一波。
總結什麼呢?異常!嗯?異常?最近卻是人有些異常……複習到一兩點,早上早早起來刷題,不異常纔怪。異常嘛,很好理解,就是本該正常的事情出了問題嘛。
這時咱們回想咱們以前寫過一個再簡單不過的例子:計算兩個整數相除。二話不說,直接就能夠寫出以下代碼,對吧。編程

public static void main(String[] args) {
    Scanner input = new Scanner(System.in);
    System.out.println("Enter two integers: ");
    int num1 = input.nextInt();
    int num2 = input.nextInt();
    System.out.println(num1 / num2);
}

這短短的代碼中就存在着隱患,而這個隱患有可能就會演變成異常。什麼狀況呢?咱們知道,在Java的整數計算中,若是除數爲零,計算式將會是沒有任何意義的。帶着咱們的猜測,編譯運行,不出所料,它飄紅了。
學習

因而,咱們對紅字進行分析,得出結論:一個名爲ArthmeticException的異常在執行main方法的第17行時發生:除數爲零。清清楚楚,明明白白。
能夠看到,異常一旦發生,程序就將終止,並且這種拋出異常的機制,可以讓咱們有效地找到問題所在,並及時解決問題。異常機制的存在,就是爲了更好地解決問題,保證程序的健壯性。
因此,咱們試圖修改代碼,讓它在方法中實現:測試

public static int quotient(int num1, int num2) throws ArithmeticException{
    if (num2 == 0) {
        throw new ArithmeticException("Divisor can not be zero");
    }
    return num1 / num2;
}

在main方法中調用查看結果:優化

int num1 = input.nextInt();
int num2 = input.nextInt();
try {
    System.out.println(QuotientWithMethod.quotient(num1, num2));
}catch (ArithmeticException e) {
    System.out.println(e.getMessage());
}

繼續測試(固然爲了測試,咱們這裏拋出了一個運行時異常,本能夠不拋):
指針

  • 在求兩數之商的方法中主動拋出(throw)一個異常,throw new ArithmeticException("Divisor can not be zero");對象。
  • 在方法定義處聲明方法將會拋出的異常類型,throws ArithmeticException
  • 在調用該方法時捕獲方法,try{...}catch (ArithmeticException e){...}並執行咱們但願處理異常的語句,System.out.println(e.getMessage());

固然,上述的例子集拋出異常、聲明異常及處理異常於一身,可是異常的內容可不只僅是這麼簡單,咱們在以後的內容中來探一探異常的究竟:code

異常的繼承體系

先來看一下異常的類繼承圖,當是不徹底統計的,由於還有還多好多的異常等待着被探索。
對象

經過圖片咱們能夠明顯的發現,這些異常的命名很是好認,果然見名知義。Throwable是全部異常的頂級父類,在它的下面有兩個大類:ExceptionError。下面是官方文檔對二者進行的解釋:blog

Error

  • 合理的應用程序出現的不該該捕獲的嚴重問題 ,合理指的是語法和邏輯上。繼承

  • 不能處理,不要嘗試用catch捕獲,只能儘可能優化。
  • 它及它的子類異常不須要在throws語句中聲明,不須要說明他們將會被拋出。
  • 它們屬於不受檢異常(unchecked exceptions)。
  • 與虛擬機相關,如系統崩潰、虛擬機錯誤、動態連接失敗等

Exception

  • Error不一樣的是,Exception表明的是一類在合理的應用程序中出現的能夠處理的問題。
  • 除了特例RuntimeException及其子類以外,Exception的其餘異常子類都是受檢異常(checked exceptions)。

異常是否受檢

unchecked exceptions(不受檢異常)

也叫運行時異常,由Java虛擬機拋出,只是容許編譯時不檢測,在沒有捕獲或者聲明的狀況下也同樣可以經過編譯器的語法檢測,因此不須要去親自捕獲或者聲明,固然要拋出該類異常也是能夠的。典型的異常類型:Error及其子類異常RuntimeException及其子類異常。注意:RuntimeException表明的是一類編程錯誤引起的異常:算數異常、空指針異常、索引越界異常、非法參數異常等等,這些錯誤若是代碼編寫方面沒有任何漏洞,是徹底能夠避免的,這也是不須要捕獲或者聲明的緣由,也有助於簡化代碼邏輯

checked expections(受檢異常)

也叫編譯時異常,Java認爲受檢異常須要在編譯階段進行處理, 必須在顯式地在調用可能出現異常的方法時捕獲(catch),或者在聲明方法時throws異常類型,不然編譯不會經過。除了上面提到的Exception及其子類都屬於受檢異常,固然,不包括上面提到的RuntimeException

異常的處理方式

咱們上面提到,咱們沒法去直接處理不受檢異常,可是咱們必須強制地對可能發生受檢異常(編譯時異常)的行爲作處理,處理方法主要有如下:

  • 在當前方法中不知道如何處理該異常時,直接在方法簽名中throws該異常類型。
public void m1() throws ClassNotFoundException, IOException {
        //to do something
    }
  • 在當前方法中明確知道如何處理該異常,就使用try{...}catch{...}語句捕獲,並在catch塊中處理該異常。
public void m3() {
        try {
            m1();
        } catch (ClassNotFoundException e) {
            //to do something
        } catch (IOException e) {
            //to do something
        }
    }

也能夠直接捕獲Exception的實例,由於它是這些異常的父類,可是上面的捕獲異常引起的錯誤會更加直接一些。

public void m2() {
        try {
            m1();
        } catch (Exception e){
            //do something
        }
    }

若是處理不了,就一直向上拋,直到有完善解決的辦法出現爲止。固然咱們也能夠自行拋出系統已經定義的異常:

public void m2(int i) throws IOException, ClassNotFoundException {
        if (i >1)
            throw new IOException("!");
        throw new ClassCastException();
    }

須要注意的是:

  • 用throw語句拋出異常的實例!注意是異常的實例!且一次只能拋出一個異常!
  • throw和throws是不同的!睜大眼睛!一個是拋出異常實例,一個是聲明異常類型。
  • 建立異常實例能夠傳入字符串參數,將被顯示異常信息。

自定義異常

咱們知道,程序發生錯誤時,系統會自動拋出異常。那麼,咱們若是想獨家定製一個屬於本身的異常能夠不?答案顯然是能夠的,情人節快到了,直接自定義一個異常:

class noGirlFriendException extends Exception{
        noGirlFriendException(){
        }
        noGirlFriendException(String msg){
            super(msg);
        }
    }

須要注意的是:

  • 若是自定義異常繼承RuntimeException,那麼該異常就是運行時異常,不須要顯式聲明類型或者捕獲。
  • 若是繼承Exception,那麼就是編譯時異常,須要處理。
  • 定義異常一般須要提供兩個構造器,含參構造器傳入字符串,做爲異常對象的描述信息

異常的捕獲方式

  • 每一個異常分別對應一個catch語句捕獲。
  • 對全部異常處理方式相同,用父類接收,向上轉型,Exception對應的catch塊應該放在最後面,否則的話,在他後面的塊沒有機會進入處理。下面就是一個典型的錯誤示範:
//下面的形式錯誤!
public static void main(String[] args) {
    try {
        System.out.println(1 / 0);
    } catch (Exception e) {
        e.printStackTrace();
    } catch (ArithmeticException e) {
        System.out.println(e.getMessage());
    }
}
  • JDK1.7以後,能夠分組捕獲異常。
    • 異常類型用豎線分開。
    • 異常變量被隱式地被final修飾。
try {
    System.out.println(1 / 0);
} catch (ArithmeticException | NullPointerException e) {
    //捕獲多異常時,異常變量被final隱式修飾
    //!false: e = new ArithmeticException();
    System.out.println(e.getMessage());
}

本文參考諸多資料,並加上自身理解,若有敘述不當之處,還望評論區批評指正。關於異常,還有一部份內容,下篇進行總結,晚安。
參考資料:
https://stackoverflow.com/questions/6115896/understanding-checked-vs-unchecked-exceptions-in-java

https://www.programcreek.com/2009/02/diagram-for-hierarchy-of-exception-classes/

https://stackoverflow.com/search?q=%5BJava%5D+Exception

相關文章
相關標籤/搜索