***基本概念
使用異常的好處是,它往往能夠降低錯誤處理代碼的複雜度。如果不使用異常,就必須檢查特定的錯誤,在程式的很多地方進行處理。而使用異常則不必在方法調用處進行檢查,因為異常機制能夠捕獲這個錯誤,並且只需在一個地方處理。而且能把執行過程代碼和錯誤處理代碼相分離。
***
Checked vs UnChecked 異常除了Error與RuntimeException,其他剩下的異常都是你需要關心的,而這些異常類統稱為Checked Exception,至於Error與RuntimeException則被統稱為Unchecked Exception.
***基本異常 當拋出異常後,java會使用new在堆上建立異常對象。然後當前的執行路徑被終止,並且從當前環境中彈出對異常對象的引用,此時,異常處理機制接管程式,並開始尋找一個恰當的地方來繼續執行程式,這個恰當的地方就是例外處理常式,它的任務是將程式從錯誤狀態中恢複,以使得程式要麼換一種方式運行,要麼繼續運行下去。 異常使得我們可以將每件事都當做一個事務來考慮,異常可以看護著這些事務的底線。 異常最重要的方面之一是如果發生問題,我們將不允許程式沿著其正常的路徑繼續走下去。
***異常說明 應把方法可能會拋出的異常告知使用此方法的用戶端程式員。使用
throws 關鍵字
void B() throws NewException{
throw new NewException();
}
***異常日誌 自訂異常類中,可以自動記錄日誌資訊;
class LoggingException extends Exception {
private static Logger logger = Logger.getLogger("LoggingException");
public LoggingException() {
StringWriter trace = new StringWriter();
printStackTrace(new PrintWriter(trace));
logger.severe(trace.toString());
}
}
更多的時候不是自訂異常類,而是捕獲別人的異常,記錄日誌的方法如下:
public class LoggingExceptions2 {
private static Logger logger = Logger.getLogger("LoggingExceptions2");
static void logException(Exception e) {
StringWriter trace = new StringWriter();
e.printStackTrace(new PrintWriter(trace));
logger.severe(trace.toString());
}
public static void main(String[] args) {
try {
throw new NullPointerException();
} catch (NullPointerException e) {
logException(e);
}
}
}
***重新拋出異常 如果只是把當前異常對象重新拋出,那麼printStackTrace()顯示的將是原來異常拋出點的調用棧資訊,而非重新拋出點的資訊。想要更新此資訊,可以採用 throw (Exception)e.fillInStackTrace();
***異常鏈 在捕獲一個異常後拋出另一個異常,並把原始異常的資訊儲存下來,稱為異常鏈。Throwable的子類中,三種基本的異常類提供了帶cause參數的構造器(Error Exception RuntimeException),其他類型的異常,應該使用initCause()方法。
***Java標準異常 Throwable對象分為兩種類型:Error表示編譯時間和系統錯誤。Exception是可以被拋出的基本類型。
***RuntimeException 運行時異常(包含RuntimeException及其子類)(不受檢查異常)會自動被java虛擬機器拋出,所以不必在異常說明中列出。這種異常屬於錯誤,將被自動捕獲。如果RuntimeException沒有被捕獲而直達main(),那麼在程式退出前將調用異常的printStackTrace()方法。 RuntimeException代表的是編程錯誤: 1 無法預料的錯誤,比如在控制範圍之外傳遞進來的null引用。 2 應該在代碼中進行檢查的錯誤。
***finally 用處:把除記憶體之外的資源恢複到初始狀態,如開啟的檔案或網路連接,在螢幕上畫的圖形,外部世界的開關等。 異常丟失: 異常不應該被忽略。但它可以輕易地忽略。在try中拋出的異常未被catch之前,在finally中再拋出異常則會覆蓋前一個異常,造成前一個異常的丟失。 從finally中return也會造成異常丟失(在finally中使用return方法會silence所有拋出的exception)。
***異常限制 在繼承結構中,子類的建構函式必須包含父類建構函式的異常聲明。衍生類別的構造器不能捕獲基類構造器拋出的異常。 子類覆蓋的方法的異常聲明必須是父類的異常聲明的子集(或父類異常聲明的衍生類別異常)。對象的可替換性得到了保證。
***構造器 異常發生時,需要確保正確清理所有東西。但在構造器內部,可能會出現異常,而此時初始化動作尚未執行完畢,因此無法在構造器內部進行清理操作。 清理的慣用方法是在建立需要清理的對象之後,立即進入一個try-finally塊,即使構造器不會拋出異常,也應該使用。如:
public class Cleanup {
public static void main(String[] args) {
try {
InputFile in = new InputFile("Cleanup.java");
try {
String s;
int i = 1;
while ((s = in.getLine()) != null )
; // Perform line-by-line processing here...
} catch (Exception e) {
System. out .println("Caught Exception in main");
e.printStackTrace(System. out );
} finally {
in.dispose();
}
} catch (Exception e) {
System. out .println("InputFile construction failed");
}
}
}