[Java] 異常處理

1. 基本異常

異常情形是指阻止當前方法或作用域繼續執行的問題。異常情形與普通問題區分在於普通問題是指在當前環境下能得到足夠的信息,總能處理這個錯誤,而對於異常情形,就不能繼續下去了,所能做的就是從當前環境跳出,並且把問題提交給上一級環境。

當拋出異常後,Java將使用new在堆上創建異常對象的引用,此時異常處理機制接管程序,並開始尋找一個恰當的地方來繼續執行,這個恰當的地方就是異常處理程序,它的任務是將程序從錯誤狀態中恢復,以使程序要麼換一種方式運行,要麼繼續運行下去。

比如,對於對象引用t,有可能在使用時尚未被初始化,所在在使用這個對象引用調用其方法之前,會先對引用進行檢查,例如:

if (t == null)
  throw new NullPointerException();

這就拋出了異常,它將在別的地方得到處理。異常使我們可以將每件事當作一個事務考慮,而異常可以看護這些事務的底線,我們在程序中可以擁有各種不同的恢復點,如果程序的某部分失敗了,異常將恢復到程序中某個已知的穩定點上。

所有標準異常類都有兩個構造器,一個是默認構造器,另一個是接受字符串作爲參數,以便能把相關信息放入異常對象的構造器,例如:

throw new NullPointerException("t = null");

在使用new創建了異常對象之後,此對象的引用將傳給throw,儘管返回的異常對象其類型通常與方法設計的返回類型不同,但從效果上看,它就像是從方法返回的。此外,能夠拋出任意類型的Throwable對象,它是異常類型的根類。


2. 捕獲異常

如果在方法內部拋出了異常,這個方法將在拋出異常的過程中結束。如果不希望方法就此結束,可以在方法內設置一個特殊的塊來捕獲異常,它是跟在try關鍵字之後的普通程序塊,例如:

try {
  // your code
}

有了異常處理機制,可以把所有動作都放在try塊裏,然後只需在一個地方就可以捕獲所有異常。拋出的異常必須在某處得到處理,以關鍵字catch表示,例如:

try {
  // your code
} catch (Type1 id1) {
  // Handle exception of Type1
} catch (Type2 id2) {
  // Handle exception of Type2
}

每個catch子句接收一個且僅接收一個特殊類型的參數的方法,它必須緊跟在try塊之後,當異常被拋出時,異常處理機制將負責搜尋參數與異常類型匹配的第一個處理程序,然後進入catch子句執行。


3. 自定義異常

要自己定義異常類,必須從已有的異常類繼承,例如:

class Simple Exception extends Exception {}

還可以更進一步自定義異常,比如加入構造器和成員,例如:

class SimpleException extends Exception {
  private int x;
  public SimpleException(String msg) {
    super(msg);
  }
}

如果把所有可能會拋出的異常告知使用此方法的客戶端程序員,它可以使調用者能確切知道寫什麼樣的代碼可以捕獲所有潛在的異常,如果提供了源代碼,客戶端程序員可以在源代碼中查找throw語句來獲知相關信息。但是程序庫通常並不與源代碼一起發佈,爲了預防這樣的問題,Java提供了相應的語法告知客戶端程序員某個方法可能會拋出的異常類型,這就是異常說明,它屬於方法聲明的一部分,緊跟在形式參數列表之後。

異常說明使用了附加的關鍵字throws,後面接一個所有潛在異常類型的列表,例如:

void f() throws TooBig, TooSmall {
  // your code
}

代碼必須與異常說明保持一致,如果方法裏的代碼產生了異常卻沒有進行處理,編譯器會發出提醒,要麼處理這個異常,要麼就在異常說明中表明此方法將產生異常。


4. 捕獲所有異常

可以只寫一個異常處理程序來捕獲所有類型的異常,通過捕獲異常類型的基類Exception就可以做到這一點,例如:

catch(Exception e) {
  System.out.println("Caught an exceptino");
}

因爲Exception是所有異常類的基類,所以它不會含有太多具體的信息,不過可以調用它從其基類Throwable繼承的方法getMessage()和getLocalizedMessage()用來獲取詳細信息,或用本地語言表示的詳細信息。打印Throwable和Throwable的調用棧軌跡可以用printStackTrace(),調用棧顯示了帶到異常拋出點的方法調用序列,fillInStackTrace()用於在Throwable對象的內部記錄棧楨的當前狀態。

Throwable這個類用來表示任何可以作爲異常被拋出的類,它可分爲兩種類型:Errow用來表示編譯時和系統錯誤,Exception是可以被拋出的基本類型,Java程序員關心的基類型通常是Exception。


5. 使用finally進行清理

對於一些代碼,可能會希望無論try塊中的異常是否拋出,它們都能得到執行,可以在異常處理程序後面加上finally子句,例如:

try {
} catch(A a1) {
  // Handler for situation A
} catch(B b1) {
  // Handler for situation B
} finally {
  // Activities that happen every time
}

對於沒有垃圾回收和析構函數自動調用機制的語言來說,finally能使程序員保證無論try塊裏發生了什麼,內存總能得到釋放,但是Java有垃圾回收機制。那麼在Java中,當要把除內存之外的資源恢復到它們的補始狀態時,就要用到finally子句,比如已經打開的文件或網絡連接,或屏幕上畫的圖形等等。



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