1. 程式人生 > >Java筆記(三)異常

Java筆記(三)異常

異常

一、概念

一)為什麼會有Java異常機制

在沒有Java異常機制的情況下,唯一的退出機制就是返回值,判斷是否異常的方法就是

返回值。方法根據是否異常返回不同的返回值,呼叫者根據不同的返回值進行判斷。每一

層方法都需要對呼叫的方法的不同返回值進行檢查和處理,程式的正常邏輯和異常邏輯混雜

到一起,使程式碼難以閱讀和維護。另外,異常畢竟是少數,程式設計師因此常常偷懶,忽略對異常

返回值的檢查,降低了程式的可靠性。

在有了異常機制後,程式的正常邏輯與異常邏輯就可以分離,異常情況就可以集中處理,異常還可以

自動向上傳遞,不再需要每層方法都進行處理,異常可不可能被自動忽略,從而處理異常的程式碼大大

減少,程式碼的可讀性,可維護性,可靠性都得到了提高。

二)Java異常處理機制

Java異常的預設處理機制:列印異常棧到螢幕,並退出程式。

異常處理機制會從當前函式查詢誰捕獲了該異常,如果這一層函式沒有捕獲就依次向

上一層函式查詢,直到主函式,如果主函式也沒有捕獲該異常,就使用預設機制,列印

異常棧資訊,並退出程式。

異常是相對於return的一種退出程式的機制可以由throw語句觸發,也可以由系統觸發。

三)異常的分類

異常可以分類為:

1)受檢(checked)異常:強制要求程式設計師處理(捕獲或者通過throws關鍵字宣告)的異常,否則編譯器會報錯。

2)未受檢(unchecked)異常:不要求程式設計師處理。

關於受檢異常和未受檢異常,以前的說法是:

未受檢異常屬於程式設計的邏輯錯誤,程式設計時應該檢查以避免這些錯誤,比如空指標異常,

如果真的出現這種錯誤,程式退出也是正常的,程式設計師應該檢查程式碼BUG而不是想辦法

處理這種異常。受檢異常表示程式本身沒問題,但由於I/O、網路、資料庫等不可預測的

錯誤導致的異常,呼叫者應該處理。

但實際上程式設計錯誤也是應該處理的,尤其Java被廣泛應用於伺服器應用中,不能

因為一個邏輯錯誤就使程式退出。所以,目前一種更被認同的的觀點是:Java中

對受檢異常和未受檢異常的區分是沒有太大意義的,可以統一使用未受檢異常來代替。

這種觀點的基本理由是:無論受檢異常還是未受檢異常,無論是否出現在throws宣告中

,都應該在合適的地方以適當的方式進行處理,而不只是為了滿足編譯器的要求盲目處理

異常,既然都要進行處理異常,受檢異常的強制宣告和處理就顯得很繁瑣,尤其在呼叫層次比較深的情況下。

異常的類體系:

1.Throwable

有四個構造方法:

1. public Throwable()
2. public Throwable(String message)
3. public Throwable(String message, Throwable cause)
4. public Throwable(Throwable cause)

其中message表示異常訊息,cause表示觸發該異常的其他異常。異常可以形成一個異常鏈,

上層的異常由底層觸發,cause表示的是底層異常。Throwable還有一個public方法用於設定cause:

Throwable initCause(Throwable cause)

Throwable某些子類沒有建構函式就可以通過該方法設定。這個方法最多隻能被呼叫一次。

2.Error

Error(unchecked):描述了Java執行時系統內部錯誤和資源耗盡錯誤。

應用程式不應該丟擲此類異常。如果出現這樣的內部錯誤,應該通報給客戶,並盡力使程式安全退出。

3.Exception

Exception層次:

RuntimeException(unchecked):由於程式錯誤(程式碼有問題)導致的異常,如

錯誤的型別轉換,

陣列訪問越界,

訪問空指標

這類異常一定是你的錯誤。

其他異常(checked):程式本身沒有問題,由於像I/O錯誤這類問題導致的異常。如:

試圖在檔案末尾後面讀取資料

試圖開啟一個不存在的檔案。

編譯器將核查是否所有checked異常提供了異常處理器。

四)異常的處理

重新丟擲:因為當前層級不能處理該異常,丟擲給呼叫者處理。

丟擲一個新異常:當前異常所包含的資訊不夠,或者太過詳細。

throws關鍵字:用於宣告一個方法可能丟擲的異常,這個宣告的

含義是這個方法可能丟擲這些異常,並且沒有對這些異常進行處理,呼叫者必須進行處理。

finally執行細節:

1)如果在try或者catch語句內有return語句,則return語句在finally語句

執行結束後才執行,但finally並不能改變返回值。

    //返回0
    public static int test(){
        int ret = 0;
        try{return ret;
        }finally{
            ret = 2;
        }
    }

2)如果在finally語句中也有return語句:try和catch中的return會丟失,實際返回finally中的返回值。

finally中有return還會掩蓋try和catch內的異常,就像沒有異常發生一樣。如果finally中丟擲了異常,

則原異常也會被覆蓋。

    public static int test(){
        int ret = 0;
        try{
            int a = 5/0;
            return ret;
        }finally{
            //返回2而不向上傳遞異常
            return 2;
        }
    }
    public static void test(){
        try{
            int a = 5/0;
        }finally{
            //原來異常ArithmeticException丟失
            throw new RuntimeException("hello");
        }
    }

因此:應該避免在finally中return或者丟擲異常,如果呼叫的其他程式碼可能丟擲異常,

則應該捕獲異常並進行處理。