1. 程式人生 > >Java基礎之----異常處理(1.7以上)

Java基礎之----異常處理(1.7以上)

什麼是異常

異常是在程式執行過程中發生的,中斷程式正常執行流程的事件.Exception是exceptional event的簡稱java程式語言用異常來處理錯誤和其他異常事件。

處理過程 當在一個方法執行過程中發生一個異常,這個方法會建立一個異常物件,並把發這個物件傳遞給執行時系統,這個過程叫丟擲異常,這個異常物件包含異常的型別以及異常發生時,程式的狀態。

執行時系統收到這個異常物件之後,就會去尋找異常處理器。系統會沿著方法呼叫的反方向,去尋找異常處理器,當找到合適的異常處理器之後,就將這個異常交給異常處理器處理,尋找異常處理器的過程叫做捕獲異常。

如果系統沒有找到異常處理器,那麼程式就會終止。否則,會執行異常處理器的邏輯,當異常處理完畢後,會執行異常處理器之後的程式碼。

捕獲或宣告規範

合法的Java程式必須遵守catch和宣告規範,也就是可能產生異常的必須被採用以下兩種方式的一種包裹: * 要麼是try{}catch{}塊 * 要麼是一個用throws宣告的方法 * 這就是捕獲或者宣告規範。Java將所有異常分為三類:受檢查異常、執行時異常和Error,其中,執行時異常和Error有稱為不受檢查異常。只有受檢查異常必須遵守這個原則。如果不遵守這個規則,那麼程式將不能通過編譯。不受檢查異常則不然,它會通過編譯,但是程式如果在執行中出錯,則會停止程式的執行

異常的分類:

異常可以分為以下三類

受檢查異常 這種異常是程式需要預料並且恢復的異常條件

Error

 這種異常是程式之外的異常條件,是程式無法意料和恢復的。應用程式可以捕獲這類異常,用以通知使用者,或者列印相應的log.在異常體系裡,Error是所有Error及其子類。它可以不受catch和宣告規範的制約。

執行時異常 這類異常是程式之內的異常,通常是由於程式裡的邏輯錯誤或者不正確使用API導致的,這類異常一般程式無法預料和恢復。通常需要消除這種異常的產生。它是Exction的子類。所有RuntimeException及其子類都是執行時異常。

幾種常見的執行時異常: ArithmeticException,ArrayStoreException,BufferOverflowException,BufferUnderflowException,IndexOutOfBoundsException,NegativeArraySizeException,NullPointerException

Error和執行時異常統稱不受檢查異常,這兩種異常不受捕獲或宣告要求的約束。但是,不受檢查異常是可以被捕獲處理的。

捕獲和處理異常

try{

}catch(Exception e){


}finally{

}

try用來包裹可能出現異常的程式碼塊

catch用來處理異常,從Java7開始,一個catch可以捕獲多個異常,可以採用以下形式宣告:

catch (IOException|SQLException ex) {
    logger.log(ex);
    throw ex;
}

但需要注意的是,當採用這種方式宣告的時候,ex預設是一個final型別的。

當異常產生時,執行時系統會將產生的異常型別和catch語句的異常型別比較,找到第一個型別和異常型別匹配catch塊便執行異常處理邏輯。所以,catch塊的順序應該按異常類層次結構從下到上的順序排列

finally塊一般在異常處理結束後最後執行,但也不一定一定會被執行。如果在執行try和catch的過程中,jvm退出或者執行這兩個塊的執行緒中斷或者kill掉了,那麼finally是不會被執行 的。這個塊通常來執行一些最後的清理工作,用於防止資源洩露

try-with-resources

resources:在程式結束後必須關閉的物件,否則會造成記憶體洩露。這些物件要麼實現了java.lang.AutoCloseable,要麼實現了java.lang.Closeable,

try-with-resources是用來宣告一個或多個資源物件的,採用這種方式宣告的資源物件,不論是否出現異常,在執行完畢後,資源物件會自動關閉。但是,在使用try-with-resources時,如果try-with-resources裡在關閉資源時產生異常,此時,如果try塊裡也產生異常,那麼try-with-resources裡產生的異常將被抑制。

宣告方法丟擲異常

如果一個方法在執行過程中可能丟擲受檢查的異常,這是我們有兩種解決方式,第一種,如果我們知道該如何處理該異常,可以直接捕獲並處理異常;第二種,如果我們不知道該如何處理,那麼我們可以交給方法呼叫棧的上游的其他方法處理,這時,我們只需要為該方法新增丟擲異常的宣告即可。如果不捕獲也不宣告丟擲,那麼,程式碼是無法通過編譯的。

受檢查異常必須採用以上兩者中的一種進行處理,不受檢查異常可以不處理,但是最好根據需要,作出合適的處理

丟擲異常

任何程式碼都可以丟擲異常,你自己的程式碼、第三方人員寫的程式碼、Java的執行時都可以丟擲異常,不管是哪裡丟擲異常,都是使用throw語句。

Java的異常處理機制定義了一系列的異常類,他們都之間或間接繼承自Throwable。在開發過程中,我們可以使用系統定義的異常類,同時也可以自己定義自己的異常類。

使用throw丟擲不受檢查異常的物件,不需要使用throws宣告,但是,如果是丟擲受檢查異常物件,那麼,必須使用throws關鍵字宣告。這裡,大家或許會有疑惑:在寫程式碼的時候,沒有使用throw關鍵字丟擲物件,為什麼還是需要使用throws關鍵字宣告?那是因為,我們呼叫的方法裡使用了throw丟擲受檢查異常。

異常類圖

可以看出,Java提供的異常類都是直接或間接繼承自Throwable,其中,Exception有一個子類RuntimeException,Error和RuntimeException及其子類,統稱為不受檢查異常,這種異常在編譯的時候不受檢查。其他的異常叫受檢查異常,在編譯的時候,編譯器會檢查是否可能發生異常並且提供了異常處理的方法,如果沒有,則無法通過編譯。

其中,

Error是程式外部發生的異常,主要是一些外部因素造成的,與程式本身無關,通常不需要處理;

RuntimeException是由於不正確的使用API或者程式自己身的邏輯錯誤造成的,通常需要通過修正程式程式碼來解決;

Exception通常是程式裡面產生的異常,程式設計師需要捕獲並處理異常,是程式從異常中恢復過來。通常處理的就是這類異常。

## 連結異常處理 ##

在我們處理異常的時候,會碰到這樣的一個情形:一個異常引發另外一個異常,這個時候就可以考慮連結異常處理。使用很簡單:

Throwable getCause()
Throwable initCause(Throwable)
Throwable(String, Throwable)
Throwable(Throwable)

Java的Throwable給我們提供了上面這些方法,我們可以在丟擲另外一個異常的時候,利用已有的異常,作為新異常產生的原因初始化新產生的異常,這就是連結異常處理。

自定義異常:

只需要繼承Throwable及其子類即可,通常情況下是繼承Exception。繼承自Error和RuntimeException的情況很少見