java基礎:異常類

java異常類有什麼用?

程序運行時,發生的不被期望的事件,它阻止了程序按照程序員的預期正常執行,這就是異常。異常發生時,是任程序自生自滅,立刻退出終止,還是輸出錯誤給用戶?或者用C語言風格:用函數返回值作爲執行狀態?。

Java提供了更加優秀的解決辦法:異常處理機制。

異常處理機制能讓程序在異常發生時,按照代碼的預先設定的異常處理邏輯,針對性地處理異常,讓程序盡最大可能恢復正常並繼續執行,且保持代碼的清晰。
Java中的異常可以是函數中的語句執行時引發的,也可以是程序員通過throw 語句手動拋出的,只要在Java程序中產生了異常,就會用一個對應類型的異常對象來封裝異常,JRE就會試圖尋找異常處理程序來處理異常。

Throwable類是Java異常類型的頂層父類,一個對象只有是 Throwable 類的(直接或者間接)實例,他纔是一個異常對象,才能被異常處理機制識別。JDK中內建了一些常用的異常類,我們也可以自定義異常。

Java異常的分類和類結構圖

Java標準庫內建了一些通用的異常,這些類以Throwable爲頂層父類。

Throwable又派生出Error類和Exception類。

錯誤:Error類以及他的子類的實例,代表了JVM本身的錯誤。錯誤不能被程序員通過代碼處理,Error很少出現。因此,程序員應該關注Exception爲父類的分支下的各種異常類。

異常:Exception以及他的子類,代表程序運行時發送的各種不期望發生的事件。可以被Java異常處理機制使用,是異常處理的核心。

其中分爲兩種異常1、檢查異常 2 、 非檢查異常

非檢查異常(unckecked exception):Error 和 RuntimeException 以及他們的子類。javac在編譯時,不會提示和發現這樣的異常,不要求在程序處理這些異常。所以如果願意,我們可以編寫代碼處理(使用try…catch…finally)這樣的異常,也可以不處理。對於這些異常,我們應該修正代碼,而不是去通過異常處理器處理 。這樣的異常發生的原因多半是代碼寫的有問題。如除0錯誤ArithmeticException,錯誤的強制類型轉換錯誤ClassCastException,數組索引越界ArrayIndexOutOfBoundsException,使用了空對象NullPointerException等等。

檢查異常(checked exception):除了Error 和 RuntimeException的其它異常。javac強制要求程序員爲這樣的異常做預備處理工作(使用try…catch…finally或者throws)。在方法中要麼用try-catch語句捕獲它並處理,要麼用throws子句聲明拋出它,否則編譯不會通過。這樣的異常一般是由程序的運行環境導致的。因爲程序可能被運行在各種未知的環境下,而程序員無法干預用戶如何使用他編寫的程序,於是程序員就應該爲這樣的異常時刻準備着。如SQLException , IOException,ClassNotFoundException 等。

簡單的來說:非檢查異常一般由代碼錯誤產生,可以不用代碼(使用try…catch…finally)處理也能通過編譯,而非檢查異常強制程序員做出代碼處理,如果不處理則不能通過編譯。

異常處理的方法

有2種不同的處理方式:使用try…catch…finally語句塊處理它。或者,在函數簽名中使用throws 聲明交給函數調用者caller去解決。

try…catch…finally

try{
     //try塊中放可能發生異常的代碼。
     //如果執行完try且不發生異常,則接着去執行finally塊和finally後面的代碼(如果有的話)。
     //如果發生異常,則嘗試去匹配catch塊。
 
}catch(SQLException SQLexception){
    //每一個catch塊用於捕獲並處理一個特定的異常,或者這異常類型的子類。Java7中可以將多個異常聲明在一個catch中。
    //catch後面的括號定義了異常類型和異常參數。如果異常與之匹配且是最先匹配到的,則虛擬機將使用這個catch塊來處理異常。
    //在catch塊中可以使用這個塊的異常參數來獲取異常的相關信息。異常參數是這個catch塊中的局部變量,其它塊不能訪問。
    //如果當前try塊中發生的異常在後續的所有catch中都沒捕獲到,則先去執行finally,然後到這個函數的外部caller中去匹配異常處理器。
    //如果try中沒有發生異常,則所有的catch塊將被忽略。
 
}catch(Exception exception){
    //...
}finally{
 
    //finally塊通常是可選的。
   //無論異常是否發生,異常是否匹配被處理,finally都會執行。
   //一個try至少要有一個catch塊,否則, 至少要有1個finally塊。但是finally不是用來處理異常的,finally不會捕獲異常。
  //finally主要做一些清理工作,如流的關閉,數據庫連接的關閉等。 
}

需要注意的地方

1、try塊中的局部變量和catch塊中的局部變量(包括異常變量),以及finally中的局部變量,他們之間不可共享使用。

2、每一個catch塊用於處理一個異常。異常匹配是按照catch塊的順序從上往下尋找的,只有第一個匹配的catch會得到執行。匹配時,不僅運行精確匹配,也支持父類匹配,因此,如果同一個try塊下的多個catch異常類型有父子關係,應該將子類異常放在前面,父類異常放在後面,這樣保證每個catch塊都有存在的意義。

3、java中,異常處理的任務就是將執行控制流從異常發生的地方轉移到能夠處理這種異常的地方去。也就是說:當一個函數的某條語句發生異常時,這條語句的後面的語句不會再執行,它失去了焦點。執行流跳轉到最近的匹配的異常處理catch代碼塊去執行,異常被處理完後,執行流會接着在“處理了這個異常的catch代碼塊”後面接着執行。
有的編程語言當異常被處理後,控制流會恢復到異常拋出點接着執行,這種策略叫做:resumption model of exception handling(恢復式異常處理模式 )
而Java則是讓執行流恢復到處理了異常的catch塊後接着執行,這種策略叫做:termination model of exception handling(終結式異常處理模式)

throws

throws聲明:如果一個方法內部的代碼會拋出檢查異常(checked exception),而方法自己又沒有完全處理掉,則javac保證你必須在方法的簽名上使用throws關鍵字聲明這些可能拋出的異常,否則編譯不通過。

throws是另一種處理異常的方式,它不同於try…catch…finally,throws僅僅是將函數中可能出現的異常向調用者聲明,而自己則不具體處理。

採取這種異常處理的原因可能是:方法本身不知道如何處理這樣的異常,或者說讓調用者處理更好,調用者需要爲可能發生的異常負責。

finally和return的關係

結論:在 try塊中即便有return,break,continue等改變執行流的語句,finally也會執行。而如果try或catch和finally中同時存在return語句則執行finally的return語句。

public static void main(String[] args)
    {
        int result;
 
        result  =  foo();
        System.out.println(result);     /////////2
 
        result = bar();
        System.out.println(result);    /////////2
    }
 
    @SuppressWarnings("finally")
    public static int foo()
    {
        trz{
            int a = 5 / 0;
        } catch (Exception e){
            return 1;
        } finally{
            return 2;
        }
 
    }
 
    @SuppressWarnings("finally")
    public static int bar()
    {
        try {
            return 1;
        }finally {
            return 2;
        }
    }

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章