【Java入門提高篇】Day16 Java異常處理(上)

pswyjz發表於2021-09-09

噹噹噹噹噹噹,各位看官,好久不見,甚是想念。

今天我們來聊聊Java裡的一個小妖精,那就是異常。

什麼是異常?什麼是異常處理?

異常嘛,顧名思義就是不正常,(逃),是Java程式執行時,發生的預料之外的事情,它阻止了程式按照程式設計師的預期正常執行。

異常處理,應該說異常處理機制,就是專門用來制服這個小妖精的法寶。Java中的異常處理機制能讓程式在異常發生時,按照程式碼的預先設定的異常處理邏輯,針對性地處理異常,讓程式盡最大可能恢復正常並繼續執行,且保持程式碼的清晰。

簡而言之,Java異常處理就是能讓我們主動迎擊可能到來的異常,並將它們以圓潤的方式處理掉。

還是先來看個小栗子,看看java裡的異常長什麼樣。

public class Test {
    public static void main(String args[]){
        int i = 0 / 0;
        System.out.println("i = " + i);
    }
}

圖片描述
別慌別慌,不要看到紅色提示就內心崩潰只想關掉IDE,來,抓緊我的手,帶你看清“異常”這個磨人的小妖精的真面目(滑稽)。

程式碼裡將0作為了分母,因此程式會發生算術異常,丟擲一個異常後,如果沒有任何處理,預設會終止程式,所以後面的列印內容並沒有輸出。在異常內容裡,有說明異常型別為:java.lang.ArithmeticException,也就是算術異常,後面跟著的是異常原因: / by zero,也就是說異常出現的原因是將0作為了分母,而且後面還有堆疊資訊,指出了異常丟擲的位置是在com.frank.chapter16.main.Test.main這個包下,Test類的第11行(這個行數如果跟你想的不一樣,不要在意,因為我的程式碼開始之前還有一些不可描述的說明資訊),因為只有一次方法呼叫,所以沒有很長的堆疊資訊,看起來也很簡潔明瞭。

所以你看,其實異常也沒那麼可怕吧,不僅給了異常原因,還告訴了你這個bug是出在第幾行,所以好好利用它,可以幫助你寫出更難以發現的bug,呸,說錯了,可以幫助你更容易找到bug(手動滑稽)。

如果不希望丟擲異常後程式就結束,而是希望它繼續執行呢?那麼就捕獲它。

如何使用異常處理

我們來把上面那個栗子改改:

public class Test {
    public static void main(String args[]){
        try{
            int i = 0 / 0;
        }catch (Exception e){
            System.out.println("好像發生異常了,但是我不管,我還要繼續執行");
        }
        System.out.println("執行完畢!");
    }
}

輸出如下:

好像發生異常了,但是我不管,我還要繼續執行
執行完畢!

好的,很強勢,現在即使丟擲了異常,程式也繼續執行了。異常就像是一頭野獸,但你一旦捕獲它,馴服它,就可以為你所用,為所欲為了。

try...catch...是常用的異常處理搭配,如果在try語句塊中發生了異常,如果剛好這個異常被捕獲到了,那麼會直接跳到catch語句塊中,執行catch語句中的程式碼,像上面的栗子裡,因為對Exception類進行了捕獲處理,所以當它的子類異常java.lang.ArithmeticException被丟擲來的時候,也能捕獲它。關於Exception類的結構層次關係,後面再做詳細介紹。

還有另外一種搭配方式,那就是try...catch...finally,finally語句塊比catch要強勢的多,前面說了catch語句塊必須要捕獲到了特定的Exception才會執行裡面的程式碼,如果catch的是ArithmeticException但是丟擲的卻是空指標異常,那就不會被捕獲了,異常也就逃之夭夭了。這個時候,finally的優勢就展示出來了,不管丟擲什麼樣的異常,也不管是否丟擲了異常,finally中的程式碼都會被執行。所以一般的用法是在finally語句塊裡釋放掉那些需要被釋放的資源,如socket連線,關閉io流,關閉資料庫連線等等。也就是說一般在finally中收拾try中丟擲的爛攤子,心疼一秒finally,果然能者多勞啊。

當然,try...finally這樣的搭配也是ok的,需要注意的是,當try語句中發生了異常之後,在發生異常處之後的程式碼將不會再執行,而是跳到相應的catchu或者finally中去。

public class Test {
    public static void main(String args[]){
        try{
            int i = 0 / 0;
        }catch (NullPointerException e) {
            System.out.println("這裡捕獲空指標異常");
        }catch (ArithmeticException e){
            System.out.println("這裡捕獲算術異常");
        }finally {
            System.out.println("這裡是finally");
        }
        System.out.println("執行完畢!");
    }
}

  輸出如下:

這裡捕獲算術異常
這裡是finally
執行完畢!

在上面的程式碼中,catch語句塊是可以同時使用多個的,第一個catch語句塊捕獲的是空指標異常,但由於丟擲的是算術異常,所以沒有捕獲住,但被第二個catch捕獲到了,所以第二個catch語句塊中的程式碼執行了。異常匹配是按照從上到下的順序進行匹配的,最後才執行finally中的程式碼塊。關於try...catch...finally,還有一個很有趣的return問題,如果三個語句塊裡都有return,最終返回結果會是怎樣呢?這裡做了詳細的說明, 有興趣的話可以看一看。

絕大多數情況下,finally中的程式碼都是會被執行的,只有一種情況下,finally中的程式碼不會被執行,那就是在try語句塊中結束掉了虛擬機器(如:使用 System.exit(0); )。

關於異常,還有一個關鍵字需要介紹,那就是throw,使用throw可以主動丟擲一個異常。看到這你也許會一臉懵逼,主動丟擲???嫌異常不夠多,湊熱鬧不嫌事大??別急別急,中間一定有什麼誤會,把刀放下,有話好好說。

throw關鍵字確實是用來丟擲異常的,你可以這樣使用:

public class Test {
    public static void main(String args[]){
        try{
            throw new NullPointerException("聽說你很閒,給你拋個異常。");
        }catch (NullPointerException e) {
            System.out.println("這裡捕獲空指標異常,提示內容:" + e.getMessage());
            e.printStackTrace();
        }
    }
}

輸出如下:

這裡捕獲空指標異常,提示內容:聽說你很閒,給你拋個異常。
java.lang.NullPointerException: 聽說你很閒,給你拋個異常。
    at com.frank.chapter16.main.Test.main(Test.java:11)

用throw關鍵字可以丟擲任意型別的異常,當然,你想的話,還有拋Error,至於什麼是Error,已經跟Exception的關係,將在下一篇裡進行講解。暫時不用深究。

在throw異常的時候,可以加上丟擲異常的原因,這樣可以更方便定位問題所在,當然,一般來說不會像栗子中這樣使用的,這裡只是為了簡單起見。

到此為止,異常的上半篇已經講解完畢,在這一篇裡,說明了什麼是異常,什麼是異常處理,以及如何使用異常處理機制。相信大家對這個小妖精有了初步的認識,下一篇中,將會講解Exception家族都有哪些成員,如何使用自定義異常,已經異常處理的實際使用中的正確姿勢。歡迎大家繼續關注,之後計劃每週兩篇以上的更新,如果有講解遺漏或者不好的地方,歡迎大家及時指出,共同進步!

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/755/viewspace-2800940/,如需轉載,請註明出處,否則將追究法律責任。

相關文章