1. 程式人生 > 其它 >【JavaSE】異常

【JavaSE】異常

異常


異常,顧名思義,就是指非正常的,在預期之外的情況。

生活中:比如郵寄一個快遞可收件人聯絡不上,這就是生活中的一個異常。

程式中:在程式執行過程中,各種異常稍不注意就會發送,從而影響程式的正常流程

常見異常如:

  • 檔案找不到
  • 網路連線失敗
  • 使用者輸入了非法資料。

注意:異常指的是在程式執行中出現的錯誤,而不是語法問題導致的編譯錯誤。

異常的分類


在Java的面向物件世界中,異常當然也是物件,眾多的異常物件就描述了各種不同的異常情況。


Java 的異常有一個頂層父類Throwable,所以的異常都繼承自它,在Throwable下又分兩大類,一個是 Error,一個是 Exception。

Error類即其子類是指我們程式處理不了或者說不該由程式處理的錯誤。
這裡的錯誤往往代表JVM在執行過程中出了問題,比如:棧溢位錯誤、記憶體不足錯誤

Exception類即其子類是指程式中可以處理的異常,我們平時最常打交道的就是這種異常。
它下面又分為兩大類:

  • 一類是RuntimeException類和其子類
  • 一個是非RuntimeException類

這兩種型別的區別就是:

  • RuntimeException 型別不強制你手動處理,比如我們最常見的空指標異常,你無需 try...catch 也無需 throws 程式碼也能編譯成功
  • 非RuntimeException 類的異常如果你不手動處理則會編譯失敗比如IO異常。

這裡延伸出一個概念:那就是受檢異常和非受檢異常。顧名思義受檢異常就是必須手動處理的異常,非受檢異常就是不強制程式處理的異常。除了 RuntimeException 外。Error 也屬於非受檢異常

如何處理異常

在Java中有兩種處理異常的方式:一個是try...catch 一個是 throws

try...catch
它就是我們常說的捕獲異常

// 可以 catch一個也可以 catch多個
try{
    // 可能會發現異常的邏輯
} catch(IOException e){
    // 發生 IOexception時,執行此程式碼塊
} catch(ClassNotFoundException e){
    // 發生 ClassNotFoundException時,執行此程式碼塊
} catch(Exception e){
    // 傳送其他異常時,執行此程式碼塊
    // 父類異常應該放在子類異常後面,否則子類異常不會被捕獲
}

我們可以將可能傳送異常的程式碼,放到 try 程式碼塊中,然後使用 catch來捕獲對應的異常。如果 try 程式碼塊正常執行,那 catch就不會生效。如果發生了指定的異常,則會執行對應的catch程式碼塊,然後繼續往下執行,如此一來,我們就能避免異常影響到我們的正常邏輯

捕獲異常時還可以接上finally 程式碼塊,無論釋出發生異常finally 程式碼塊都會執行

throws
處理try...catch外還可以使用 throws來處理異常,在方法上使用 throws關鍵字可以宣告該方法可能丟擲的異常

// 可以 throws宣告一哥異常,也可以宣告多個
public static void process() throws IDException,ClassNotFoundException{
    // 可能傳送異常的邏輯
}

當我們呼叫一個方法時,如果這個方法用 throws關鍵字聲明瞭受檢異常

public static void process() throws IOException,ClassNotFoundException{
    // ...
}

public static void f1(){
    process();// 編譯失敗,因為沒有處理受限異常
}

public static void f2(){
    try {
	process();//編譯成功
    } catch (IOException | ClassNotFoundException e){
	// ...
    }
}

public static void f3() throws IOException,ClassNotFoundException{
    process();// 編譯成功
}

此時我們就必須得手動處理它宣告的異常,否則就會編譯失敗。要麼你就 try...catch要麼你就在當前方法使用 throws宣告同樣的或其父類異常。

這裡其實就可以體現出throws的作用了

那就是我不想處理這個異常時,我可以把問題往外拋,誰呼叫我誰就來處理,就好像在工作中出現了一個問題:你可以選擇將這個問題自行解決,也可以將這個問題丟給你的上級解決,而你的上級碰到問題時,也會面臨同樣的選擇:要麼他自己解決,要麼他將問題拋給更上級。

如果一個問題或者是一個異常,發生後就一直往上拋。

public static void main(String[] args)throws Exception
{    // 如果發生異常,則程式終止
}

到最頂層的main 方法了都沒人去try...catch 解決,那程式就會終止執行

呼叫時機
一個很簡單的原則:

try{
    process();
} catch (Exception e){
    // ...
}

// 上面傳送異常,這裡也能執行
xxx();

如果當前方法需要繼續執行下去,就肯定得用 try...catch,當前方法不需要繼續執行就可以選擇throws

建議:儘量選擇捕獲異常

異常必須丟給上一層去解決,這種情況畢竟在少數。
這也是為什麼在設計自定義異常時都強烈建議繼承RuntimeException,因為這會讓你省去很多麻煩