【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,因為這會讓你省去很多麻煩