究竟什麼是Java異常?

第四階段 IO

異常處理

沒有完美的程序,因此咱們須要不斷地完善,考慮各類可能性,咱們要將除了本身之外的任何用戶或者操做者都當成傻子來考慮問題java

在咱們開發過程當中 咱們運行時經常會遇到 這樣java.lang.XxxException的信息,這表明程序發生了一些錯誤,也叫做異常程序員

(一) 概述及體系

(1) 概述

異常情形是指阻止當前方法或者做用域繼續執行的問題 ——《Think in Java》數據庫

簡單歸納:程序出現不正常狀況後,程序將會跳出當前環境,而且拋出異常。編程

(2) 體系

(1) Error —— 錯誤:程序沒法處理的嚴重錯誤,咱們不做處理數組

  • 這種錯誤通常來講與操做者無關,而且開發者與應用程序沒有能力去解決這一問題,一般狀況下,JVM會作出終止線程的動做

(2) Exception —— 異常:異常能夠分爲運行時異常和編譯期異常函數

  • RuntimeException:即運行時異常,咱們必須修正代碼測試

    • 這些異常一般是因爲一些邏輯錯誤產生的spa

      這類異常在代碼編寫的時候不會被編譯器所檢測出來,是能夠不須要被捕獲,可是程序員 也能夠根據須要行捕獲拋出,(不受檢查異常)這類異常一般是能夠被程序員避免的。 常見的RUNtimeException有:NullpointException(空指針異常),ClassCastException (類型轉 換異常),IndexOutOfBoundsException(數組越界異常)等。線程

  • 非RuntimeException編譯期異常,必須處理,不然程序編譯沒法經過指針

    • 這類異常在編譯時編譯器會提示須要捕獲,若是不進行捕獲則編譯錯誤。
    • 常見編譯異常有:IOException(流傳輸異常),SQLException(數據庫操做異常)等。

Java內置異常類

A:Java 的非檢查性異常

異常 描述
ArithmeticException 當出現異常的運算條件時,拋出此異常。例如,一個整數"除以零"時,拋出此類的一個實例。
ClassCastException 拋出表示代碼嘗試將對象轉換爲不屬於實例的子類。 例如:將Integer型對象轉換爲String類
IllegalArgumentException 拋出的異常代表向方法傳遞了一個不合法或不正確的參數。
NumberFormatException 拋出以表示應用程序已嘗試將字符串轉換爲其中一個數字類型,但該字符串不具備相應的格式。
IllegalStateException 表示在非法或不適當的時間調用了一種方法。 換句話說,Java環境或Java應用程序對於請求的操做並不處於適當的狀態。
IndexOutOfBoundsException 指示某排序索引(例如對數組、字符串或向量的排序)超出範圍時拋出。 應用程序能夠將此類子類化以指示相似的異常。
ArrayIndexOutOfBoundsException 用非法索引訪問數組時拋出的異常。若是索引爲負或大於等於數組大小,則該索引爲非法索引。
NoSuchElementException 被各類訪問器方法拋出,表示被請求的元素不存在。
InputMismatchException 輸入類型不匹配異常,通常出現此類異常的緣由就是定義的接受輸入值的變量的類型與輸入的數值的類型不匹配致使的異常。
NullPointerException 空指針異常

B:Java的檢查性異常

異常 描述
ClassNotFoundException 應用程序試圖加載類時,找不到相應的類,拋出該異常。
CloneNotSupportedException 當調用 Object 類中的 clone 方法克隆對象,但該對象的類沒法實現 Cloneable 接口時,拋出該異常。
InstantiationException 當試圖使用 Class 類中的 newInstance 方法建立一個類的實例,而指定的類對象由於是一個接口或是一個抽象類而沒法實例化時,拋出該異常。

(二) 異常處理語句

(1) try-catch

A:捕獲單個異常

try{
    //程序代碼
}catch (ExceptionName e1){
	//Catch塊
}
複製代碼

B:多重捕獲塊

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

try:用於監聽異常

catch:用於捕獲處理異常

try 後面的一對大括號內的內容即受到監控的程序,也就是說這一段代碼是可能存在異常的,而Catch中由開發者,根據自身推斷可能存在的異常,書寫對應異常類型以及處理方式,當程序發生異常時,會建立異常對象,而且將異常拋出到此環境外,Java運行時系統會尋找與發生異常所匹配的catch子句,當找到一個對應語句後則再也不尋找其餘catch塊

public class Demo {
    public static void main(String[] args) {
        int a = 520;
        int b = 0;
        int c;

        try {
            System.out.println("這是一個被除數爲0的式子");
            c = a / b;
        } catch (ArithmeticException e) {
            System.out.println("除數不能爲0");
        }
    }
}

//運行結果
這是一個被除數爲0的式子
除數不能爲0
複製代碼

經過上例能夠看到,被監控的語句中先依次正常執行,當遇到存在問題的語句時,找到匹配異常,而且執行catch塊中的語句

而通常來講咱們會在catch語句塊中經過異常對象執行異常方法

方法方法 說明
public String getMessage() 回關於發生的異常的詳細信息。這個消息在Throwable 類的構造函數中初始化了
public Throwable getCause() 返回一個Throwable 對象表明異常緣由
public String toString() 使用getMessage()的結果返回類的串級名字
public void printStackTrace() 打印toString()結果和棧層次到System.err,即錯誤輸出流

咱們仍是用上面的例子給出異常方法的測試

System.out.println(e.getMessage());

/ by zero
複製代碼
System.out.println(e.getCause());

null
複製代碼
System.out.println(e.toString());

java.lang.ArithmeticException: / by zero
複製代碼
e.printStackTrace();

java.lang.ArithmeticException: / by zero
	at cn.bwh_01_Throwable.Demo.main(Demo.java:10)
複製代碼

(2) try-catch-finally

咱們在 try-catch的基礎上再補充一個finally的知識

finally 關鍵字用來建立在 try 代碼塊後面執行的代碼塊不管是否發生異常,finally 代碼塊中的代碼總會被執行,在 finally 代碼塊中,能夠運行清理類型等收尾善後性質的語句,finally 代碼塊出如今 catch 代碼塊最後,語法以下:

try{
	......
}catch(異常類型1 異常的變量名1){
	......
}catch(異常類型2 異常的變量名2){
	......
}finally{
	......
}
複製代碼

不管是否發生異常,fianlly始終都是會運行的

這裏就不得不提一個很是重要的注意點,那就是當return遇到finally

注意點

A:return遇到finally

咱們來看下面一個例程:

public class Demo2 {
    public static void main(String[] args) {
        System.out.println(test());
    }

    public static String test(){
        int[] array = new int[2];
        try{
            array[3] = 0;
            return "This is try";
        }catch (ArrayIndexOutOfBoundsException e){
            System.out.println(e);
            return "This is catch 1";
        }catch (Exception e){
            System.out.println(e);
            return "This is catch 2";
        }finally {
            System.out.println("This is finally");
            //return "This is finally's return";
        }
    }
}

//運行結果
java.lang.ArrayIndexOutOfBoundsException: 3
This is finally
This is catch 1
複製代碼

由此咱們得出一個結論:在catch中遇到return時,仍然會先執行finally語句,再回來執行對應catch語句中的return語句

可是咱們若是將finally中return行中的註釋去掉,運行結果就會變成下面這樣子

//運行結果
java.lang.ArrayIndexOutOfBoundsException: 3
This is finally
This is finally's return
複製代碼

結果就是返回值會被finally中的return語句從新覆蓋

B:catch 順序問題
public class Demo3 {
    public static void main(String[] args) {
        int[] array = new int[2];
        try{
            array[5] = 0;
        }catch (Exception e){

        }catch (ArrayIndexOutOfBoundsException e){

        }
    }
}

//運行結果
Error:(8, 10) java: 已捕獲到異常錯誤java.lang.ArrayIndexOutOfBoundsException
複製代碼

對於多個catch的狀況,當try中程序發生異常,會按照從上往下的順序與catch進行匹配,一旦與其中一個匹配後就不會再與後面的catch進行匹配了,因此,在書寫catch語句的時候,必定要把範圍小的放在前面,範圍大的放在後面!

(3) throw/throws

將本身處理不了的,在方法或者語句上聲明,告訴調用者,這裏有問題

若是一個方法沒有捕獲到檢查性異常,那麼該方法就必須使用throws關鍵字聲明(聲明拋出多個異常,之間使用逗號隔開),也能夠在語句中使用throw關鍵字拋出一個異常。

//演示throw
public class Demo4 {
    public static void main(String[] args) {
        test();
    }

    public static void test() {
        int a = 520;
        int b = 0;
        if (b == 0) {
            throw new ArithmeticException();
        } else {
            System.out.println(a / b);
        }
    }
}

//運行結果
Exception in thread "main" java.lang.ArithmeticException
複製代碼
//演示throws

public class Demo4 {
    public static void main(String[] args) {
        try {
            test();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void test() throws Exception {
        int a = 520;
        int b = 0;
        if (b == 0) {
            throw new Exception();
        } else {
            System.out.println(a / b);
        }
    }
}

//運行結果
java.lang.Exception
複製代碼
throws和throw的區別

A:throws

  • 用在方法聲明後,跟的是異常類名
  • 能夠跟多個異常類名,用逗號隔開
  • 表示拋出異常,由該方法的調用者來處理
  • throws表示出現異常的一種可能性,不必定會發生這些異常

B:throw

  • 用在方法體內,跟的是異常對象名

  • 只能拋出一個異常對象名

  • 表示拋出異常,由方法體內的語句處理

  • 執行throw則必定拋出了某種異常

(三) 自定義異常

Java內置的異常類,基本能夠知足咱們在編程中遇到的大部分異常狀況,此外咱們還能夠自定義異常類,只須要繼承Exception類便可

基本步驟:

  • 建立自定義異常類

  • 在方法中經過throw拋出異常對象

    • 在當前拋出異常的方法中處理異常,可使用try-catch語句捕獲處理
    • 也能夠在方法聲明處使用throws將異常拋給方法調用者
  • 在出現異常方法的調用者中捕獲而且處理異常

class MyException extends Exception {  // 自定義的類
    MyException(String s) {
        super(s);
    }
}
class Demo {
    void method() throws MyException {
        throw new MyException("Wrong"); // 拋出自定義的類
    }
}
class DemoTest {
    public static void main(String[] args){
        try {
            new Demo().method();
        }
        catch(MyException e) {
            System.out.println(e.getMessage());
        }
    } 
}

//運行結果
Wrong
複製代碼

(三) 總結

異常就是在程序發生異常時,強制終止程序運行,而且將異常信息返回,由開發者決定是否處理異常

簡單說一下這個異常機制的過程:

當程序沒法運行後,它會從當前環境中跳出,而且拋出異常,以後,它會先new一個異常對象,而後在異常位置終止程序,而且將異常對象的引用從當前環境中返回,這時候異常處理機制接管程序,而且開始尋找能夠繼續執行程序的恰當位置。

結尾:

若是內容中有什麼不足,或者錯誤的地方,歡迎你們給我留言提出意見, 蟹蟹你們 !^_^

若是能幫到你的話,那就來關注我吧!(系列文章均會在公衆號第一時間更新)

在這裏的咱們素不相識,卻都在爲了本身的夢而努力 ❤

一個堅持推送原創Java技術的公衆號:理想二旬不止

相關文章
相關標籤/搜索