異常處理的優點之一是你可以在某處集中精力處理你要解決的問題,而在另一處處理你編寫的這段代碼中產生的錯誤。對於異常情形,在 當前環境下 無法獲得必要的信息來解決問題,而是從當前環境跳出,並把問題交給上一級環境。
當拋出異常後,同其他對象的創建一樣,使用new在堆上創建異常對象,當前的執行路徑被終止,並且從當前環境中彈出對異常對象的引用。此時, 異常處理機制 接管程序,異常處理程序將程序從錯誤狀態中恢復,使程序要麼換一種方式執行,要麼繼續運行。
異常參數:所有標準的異常類都有兩個構造器:一個是默認構造器,另一個是接受字符串作爲參數,以便能把有關信息放入異常對象的構造器。
異常處理模型:終止和恢復
終止模型:java支持終止模型,一旦異常被拋出,就表明錯誤已經無法挽回,也就不能回來繼續執行。
恢復模型:通常希望異常被處理之後能繼續執行程序。
1. 處理異常機制
異常處理機制:拋出異常、捕獲異常
拋出異常:當一個方法出現錯誤引發異常時。方法創建異常對象並交付運行時系統,異常對象中包含了異常類型和異常出現時的程序狀態等異常信息。運行時系統負責尋找處置異常的代碼並執行。
throws拋出異常:如果一個方法可能會出現異常,但沒有能力處理這種異常,可以在方法聲明處用throws子句來聲明要拋出的異常類型。throws將異常拋出給調用者後,如果調用者不想處理該異常,可以繼續向上拋出但最終要有能夠出來了該異常的調用者。
捕獲異常:方法拋出異常後,運行時系統轉爲尋找合適的異常處理器。潛在的異常處理器是異常發生時一次存留在調用棧中的方法集合。運行時系統從發生異常的方法開始,一次回查調用棧中的方法,直至找到含有合適異常處理器的方法並執行。反之,java程序終止。
2 . 捕獲所有的異常
Exception 是與編程有關的所有異常類的基類,不會包含太多具體的信息,不過可以調用它從其基類Throwable繼承的方法。
String getMessage() //返回Throwable的詳細消息字符串
String getLocalizedMessage() //返回Throwable的本地化描述
String toString() //返回此Throwable的簡短描述
void printStackTrace()//將此Throwable及其追蹤輸出至標準錯誤流
void pritnStackTrace(PrintStream) //將此Throwable及其追蹤輸出到指定的輸出流
void printStackTrace(java.io.PrintWriter) //將此Throwable及其追蹤輸出到指定的PrintWriter
1.1 異常鏈
在捕獲一個異常後拋出另一個異常,並且希望把原始異常的信息保存下來,這就稱爲異常鏈。
現在所有的Throwablede的子類在構造器中都可以接受一個cause作爲參數,這個cause就用來表示原始異常,這樣通過把原始異常傳遞給新異常,即使在當前位置創建並拋出了新的異常,也能通過這個異常鏈追蹤到異常最初發生的位置。在Throwable子類中,只有三種基本的異常類提供了帶參數的cause參數的構造器,就是Exception、Error、RuntimeException。如果把其他類型的異常鏈接起來,應該使用initCause()方法而不是構造器。
3. java 標準異常
Throwable 對象可以分爲兩種類型:Error用來表示編譯時和系統錯誤,Exception 是可以被拋出的基本類型。
Error:是程序無法處理的錯誤,表示運行應用程序中較嚴重的問題。大多數錯誤與編寫者執行的操作無關,而表示代碼運行時JVM出現問題。這些錯誤表示故障發生於虛擬機自身、或者發生在虛擬機試圖執行應用時。這些錯誤時不可查的,因爲他們在應用程序的控制和處理能力之外。Exception是程序本身可以處理的異常。java的異常(Excdeption和Error)分爲可查的異常和不可查的異常。
可查異常(編譯器要求必須處置的異常):除RuntimeException及其子類以外,其他的Exception類及其子類都屬於可查異常。它們的特點是JAVA編輯器會檢查它,也就是說,當程序中可能出現這類異常,要麼用try-catch語句捕獲它,要麼用throws子句聲明拋出它,否則編譯不會通過。
不可檢查的異常。包括運行時異常和錯誤。
運行時異常會自動被java虛擬機拋出,這些異常都是從RuntimeException類繼承而來。 只能在代碼中忽略RuntimeException類型的異常,其他類型異常的處理都是由編譯器強制實施的。因爲RuntimeException 代表的是編程錯誤。
4.使用finally進行清理
finally字句總能得到執行,它用來將除內存以外的資源恢復到他們的初始狀態,需要清理的資源包括:已經打開的文件或網絡連接,在屏幕上畫的圖形等。當在try塊或catch中遇到return語句時,finally語句將在方法返回之前被執行。有四種情況,finally不會被執行:
- 在finally語句塊中發生了異常
- 在前面的代碼中使用了Systen.exit()退出程序
- 程序所在的線程死亡
- 關閉CPU
從finally中返回,有可能會導致異常的丟失。
5.異常的限制
當覆蓋方法的時候,只能拋出在基類方法的異常說明裏列出的那些異常。
派生類的構造器不能捕獲基類構造器所拋出的異常。當拋出異常時,編譯器不會創建對象。不能從異常失敗中“恢復”,因爲沒有基類子對象。
package exception;
//方法被覆蓋時,只能拋出在基類方法的異常說明裏列出來的那些異常。
class BaseballException extends Exception {}
class Foul extends BaseballException {}
class Strike extends BaseballException {}
abstract class Inning {
public Inning() throws BaseballException {}
public void event() throws BaseballException {
}
public abstract void atBat() throws Strike, Foul;
public void walk() {}
}
class StormException extends Exception {}
class RainedOut extends StormException {}
class PopFoul extends Foul {}
interface Storm {
public void event() throws RainedOut;
public void rainHard() throws RainedOut;
}
public class StormyInning extends Inning implements Storm {
//異常限制對構造器不起作用,可以爲構造器添加新的異常,但是派生類構造器的異常說明必須包含基類構造器的異常說明
//派生類構造器不能捕獲基類構造器拋出的異常
public StormyInning()
throws RainedOut, BaseballException {}
public StormyInning(String s)
throws Foul, BaseballException {}
//基類方法未拋出異常,所以導出類不能拋出異常
//void walk() throws PopFoul {} //Compile error
//接口不能爲現存的來自基類的方法增加異常
//! public void event() throws RainedOut {}
public void rainHard() throws RainedOut {}
//可以不拋出任何異常,即使基類中定義了異常
public void event() {}
// Overridden methods can throw inherited exceptions:
//重載的方法可以拋出繼承的異常
public void atBat() throws PopFoul {}
public static void main(String[] args) {
try {//僅捕獲這個類所拋出的異常
StormyInning si = new StormyInning();
si.atBat();
} catch(PopFoul e) {
System.out.println("Pop foul");
} catch(RainedOut e) {
System.out.println("Rained out");
} catch(BaseballException e) {
System.out.println("Generic baseball exception");
}
try {
// 向上轉型
Inning i = new StormyInning();
i.atBat();
//必須捕獲來自基類方法的異常
} catch(Strike e) {
System.out.println("Strike");
} catch(Foul e) {
System.out.println("Foul");
} catch(RainedOut e) {
System.out.println("Rained out");
} catch(BaseballException e) {
System.out.println("Generic baseball exception");
}
}
}
6.異常匹配
拋出異常時,異常處理系統會按照代碼書寫順序找出最近的處理程序,當找到匹配的處理程序後,將不再會查找。查找的時候並不要求拋出的異常同處理程序所聲明的異常完全匹配。派生類的對象也可以匹配其基類的處理程序。