通過異常處理錯誤

異常處理的優點之一是你可以在某處集中精力處理你要解決的問題,而在另一處處理你編寫的這段代碼中產生的錯誤。對於異常情形,在 當前環境下 無法獲得必要的信息來解決問題,而是從當前環境跳出,並把問題交給上一級環境。


當拋出異常後,同其他對象的創建一樣,使用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不會被執行:


  1. 在finally語句塊中發生了異常
  2. 在前面的代碼中使用了Systen.exit()退出程序
  3. 程序所在的線程死亡
  4. 關閉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.異常匹配


拋出異常時,異常處理系統會按照代碼書寫順序找出最近的處理程序,當找到匹配的處理程序後,將不再會查找。查找的時候並不要求拋出的異常同處理程序所聲明的異常完全匹配。派生類的對象也可以匹配其基類的處理程序。

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