Java異常

異常概述java

異常也稱爲例外,是在程序運行過程當中發生的而且會打斷程序正常執行的事件,好比算術異常、空指針異常、文件找不到異常。因此在程序設計時,必須考慮到可能發生的異常事件,並作出相應的處理。這樣才能保證程序能夠正常運行。數組

Java的異常處理機制也秉承着面向對象的基本思想,在Java中,全部的異常都是以類的形式存在,除了內置的異常類以外,Java也能夠自定義異常類。此外,Java的異常處理機制也容許自定義拋出異常。網絡

 

爲何要使用異常架構

在沒有異常處理的語言中,就必須使用if或switch等語句,配合所想獲得的錯誤情況來捕捉程序裏全部可能發生的錯誤。但爲了捕捉這些錯誤,編寫出來的代碼常常有不少的if語句,有時候這樣也未必能捕捉到全部的錯誤,並且這樣作勢必致使程序運行效率的下降。Java的異常處理機制剛好改進了這一點,它易於使用而且可自行定義異常類,可是不得不說,異常也是一個較爲耗費性能的操做,所以咱們須要合理地利用Java的異常處理機制,以增進程序的穩定性和效率。性能

 

異常的繼承架構spa

異常可分爲兩大類:java.lang.Exception與java.lang.Error,這兩個類均繼承自java.lang.Throwable,上圖爲Throwable類的繼承關係圖。設計

習慣上將Error與Exception統稱爲異常類,但這二者本質上仍是有不一樣的:指針

一、Error專門用來處理嚴重影響程序運行的錯誤,但是一般程序設計者不會涉及程序代碼去捕捉這種錯誤,其緣由在於即便捕捉到它,也沒法給予適當的處理,好比Java虛擬機出錯就屬於一種Errorcode

二、Exception包含了通常性的異常,這些異常一般在捕捉到以後即可以作妥善的處理,以確保程序繼續運行對象

從繼承架構圖中能夠看出,Exception擴展出數個子類,其中IOException、RuntimeException是較經常使用的兩種。RuntimeException即便不編寫異常處理的程序代碼,依然能夠編譯成功,而這種異常必須是在程序運行時纔有可能發生,好比數組索引值超出了範圍。與RuntimeException不一樣的是,IOException必定要編寫異常處理的程序代碼才行,它一般用來處理輸入/輸出相關的操做,如對文件的訪問、網絡的鏈接等。

當異常發生時,發生異常的語句代碼會拋出一個異常類的實例化對象,以後此對象與catch語句中的類的類型進行匹配,而後在相應的catch中進行處理。

 

try、catch、finally、throw、throws

當異常發生時,一般能夠用兩種方法來處理:

一、交由Java默認的異常處理機制作處理,但這種處理方式,Java一般只能輸出異常信息,接着便終止程序的運行,好比:

 1 public static void main(String[] args) throws InterruptedException
 2 {
 3     operateNull(null);
 4     System.out.println("After operateNull");
 5 }
 6 
 7 public static char operateNull(String str)
 8 {
 9     return str.charAt(0);
10 }

返回結果爲:

Exception in thread "main" java.lang.NullPointerException
    at com.xrq.test33.TestMain.operateNull(TestMain.java:13)
    at com.xrq.test33.TestMain.main(TestMain.java:7)

和"接着便終止程序的運行"一致,由於第4行的語句並無打印。

二、自行編寫try-catch-finally塊來捕捉異常,這種寫法的最大好處是,能夠靈活操控程序的流程且可作出最適當的處理,好比:

 1 public static void main(String[] args) throws InterruptedException
 2 {
 3     try
 4     {
 5         Thread.sleep(1000);
 6         operateNull(null);
 7     } 
 8     catch (NullPointerException e)
 9     {
10         System.out.println("NullPointerException's catch block!");
11         throw e;
12     }
13     finally
14     {
15         System.out.println("NullPointerException's finally block!");
16     }
17 }
18 
19 public static char operateNull(String str)
20 {
21     return str.charAt(0);
22 }

返回結果爲:

1 NullPointerException's catch block!
2 NullPointerException's finally block!
3 Exception in thread "main" java.lang.NullPointerException
4     at com.xrq.test33.TestMain.operateNull(TestMain.java:25)
5     at com.xrq.test33.TestMain.main(TestMain.java:10)

關於這段代碼解釋每一個關鍵字:

(1)try表示要檢查的程序語句

(2)catch表示異常發生時的處理語句,可省略

(3)finally表示不管catch內部寫了什麼,即便是return,也都會運行到的語句,可省略。finally經常使用於對某段待檢查的代碼作掃尾工做,好比ReentrantLock的unlock()、IO的close()

(4)throw表示拋出一個類的實例,注意實例二字,實例意味着throw出去的是一個實例化的異常對象。因此代碼的11行也能夠寫爲"throw new NullPointerException()",至於爲何不這麼寫,由於寫"throw new NullPointerException()"並無返回結果中第4行、第5行中的異常堆棧。注意,throw關鍵字能夠寫在任何地方,並不強制必須寫在catch塊中,運行到throw所在的行,打印異常並當即退出當前方法

(5)throws用於方法聲明,表示若是方法內的程序代碼可能會發生異常,且方法內又沒有使用代碼的代碼塊來捕捉這些異常時,則必須在聲明方法時一併指明全部可能發生的異常,以便讓調用此方法的程序得以作好準備來捕捉異常。好比"方法名稱(參數...) throws 異常類1, 異常類2, 異常類3...",也能夠不這麼麻煩,Exception是全部異常的父類,所以也能夠直接"方法名稱(參數...) throws Exception"

 

異常場景彙總

異常細節諸多,以前我也一直有搞不清楚的地方,所以這裏對多種場景作一個總結、彙總:

一、接口方法能夠throws異常,但必須throws一個具體的異常,不能直接throws出去Exception

public interface InterfaceException
{
    void ExceptionMethod() throws NullPointerException;
}

二、接口方法throws異常,其實現類實現該方法的時候不強制必須拋出該異常,也能夠任意拋出異常

public class InterfaceExceptionImpl implements InterfaceException
{
    public void ExceptionMethod()
    {
        
    }
}
public class InterfaceExceptionImpl implements InterfaceException
{
    public void ExceptionMethod() throws ArrayIndexOutOfBoundsException
    {
        
    }
}

三、catch塊內若是捕獲到了異常而且throw出去了e,那麼方法以後的代碼都不會再運行了;catch塊內若是捕獲到了異常,可是沒有throw出去e,也沒有任何致使程序終止的語句,那麼try...catch...finally以後的語句仍然能夠繼續運行

四、捕獲異常不能夠先catch (Exception e){...}再catch (NullPointerException e)

緣由是"Unreachable catch block for NullPointerException. It is already handled by the catch block for Exception",即Java檢測到NullPointer這個異常是不可達的

五、方法A聲明throws異常,則調用方法A的代碼必須try...catch...該異常

六、方法A聲明throws出Exception,調用方法A的代碼必須try...catch...該異常,若是:

(1)有匹配異常的catch塊,則優先走匹配異常的catch塊

(2)若是沒有匹配異常的catch塊,可是有catch (Exception e){...},則走catch (Exception e){...}

(3)若是沒有沒有匹配的catch塊,則調用方法A的地方throw異常,方法終止

七、若是方法中沒有try...catch異常而該方法發生了異常,且方法聲明中有throws,那麼發生的該異常能夠被拋到調用方法的代碼中

八、若是方法中對某個代碼塊作了try...catch而且想把catch到的異常拋給調用方法的地方,那麼:

(1)不能夠只有throw沒有throws,這將會致使捕獲到的異常沒法被拋給調用方法的地方

(2)不能夠只有throws沒有throw,這將會致使編譯出錯

只有在catch塊中throw捕獲到的異常而且在方法聲明的地方throws異常,才能夠將一個異常正確地拋給調用方法的地方

相關文章
相關標籤/搜索