Java基礎之----異常處理(1.7以上)
什麼是異常
異常是在程式執行過程中發生的,中斷程式正常執行流程的事件.Exception是exceptional event的簡稱java程式語言用異常來處理錯誤和其他異常事件。
處理過程 當在一個方法執行過程中發生一個異常,這個方法會建立一個異常物件,並把發這個物件傳遞給執行時系統,這個過程叫丟擲異常,這個異常物件包含異常的型別以及異常發生時,程式的狀態。
執行時系統收到這個異常物件之後,就會去尋找異常處理器。系統會沿著方法呼叫的反方向,去尋找異常處理器,當找到合適的異常處理器之後,就將這個異常交給異常處理器處理,尋找異常處理器的過程叫做捕獲異常。
如果系統沒有找到異常處理器,那麼程式就會終止。否則,會執行異常處理器的邏輯,當異常處理完畢後,會執行異常處理器之後的程式碼。
捕獲或宣告規範
合法的Java程式必須遵守catch和宣告規範,也就是可能產生異常的必須被採用以下兩種方式的一種包裹: * 要麼是try{}catch{}塊 * 要麼是一個用throws宣告的方法 * 這就是捕獲或者宣告規範。Java將所有異常分為三類:受檢查異常、執行時異常和Error,其中,執行時異常和Error有稱為不受檢查異常。只有受檢查異常必須遵守這個原則。如果不遵守這個規則,那麼程式將不能通過編譯。不受檢查異常則不然,它會通過編譯,但是程式如果在執行中出錯,則會停止程式的執行
異常的分類:
異常可以分為以下三類
受檢查異常 這種異常是程式需要預料並且恢復的異常條件
Error
執行時異常 這類異常是程式之內的異常,通常是由於程式裡的邏輯錯誤或者不正確使用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的情況很少見