Java--異常與錯誤區別 Error and Exception

 

許多程序員並沒有意識到一個錯誤和一個異常是有區別的,在出現問題時,這種區別對如何操作你的代碼有很重要的含意(見工具條,“簡介錯誤與異常”)。正如Mary Campione在The Java Tutorial(Java指南)中所寫的,“一個異常是在一個程序執行過程中出現的一個事件,它中斷了正常指令的運行。”根據American Heritage Dictionary的解釋,一個錯誤是“偏離了可接受的代碼行爲的一個動作或一個實例。”

那麼偏離(deviation)和中斷(disruption)有什麼不同呢?我們可以這麼來解釋:如果你正在一條路上駕駛,有人截住了你,這就是中斷。如果車發動不了了,那就是偏離(除非是我的車,我們認爲這種情況是normal的)。

這同Java有什麼關係呢?有很大的關係。Java有個很有趣的錯誤和異常層次關係(見圖1)。

的確,運用try {} catch (Exception e) {}的所有代碼只能找到一半你的錯誤。但是你是否應該截獲Throwable取決於你一旦截獲了它,你準備怎麼處理它。對Error的子集的快速瞭解可以讓你知道許多類的名字,如VirtualMachineError、ThreadDeath和LinkageError。在你打算截獲這些錯誤時,確信你要處理它們,因爲它們是嚴重的問題,所以是錯誤。

 

圖1.
圖1.

但ClassCastException不是一個錯誤嗎?的確不是。一個ClassCastException——或一種異常——只是VM(虛擬機)通知你的一種方式,通過這種方式,VM讓你知道,你(開發人員)已經犯了個錯誤,現在有一個機會來修改它。

 

另一方面,錯誤是VM的一個故障(雖然它可以是任何系統級的服務)。我們來引用JavaDoc對Error的定義:“Error是Throwable的一個子集,它指的是一個合理的應用程序不能截獲的嚴重的問題。大多數都是反常的情況。”

所以,錯誤是很難處理的,一般的開發人員(當然不是你)是不能理解處理這些錯誤的微妙之處的。那麼在你的工作中,當你覺得會產生一個足以被稱爲錯誤的一個事件時,該怎麼辦呢?

首先,記住錯誤是像異常一樣被拋出的,只有一點不同。拋出一個錯誤的方法不需要聲明它在做什麼(換句話說,異常是unchecked):

public void myFirstMethod() throws Exception
    //Since it's an exception, I have to declare 
    //it in the throws clause {
    throw new Exception();
}

public void mySecondMethod()
    //Because errors aren't supposed to occur, you 
    //don't have to declare them. 
{
    throw new Error();
}

 

注意有幾個異常是unchecked的,因此,其行爲就同錯誤一樣:NullPointerException、ClassCastException和IndexOutOfBoundsException都是RuntimeException的子類,RuntimeException及其所有的子集通常都是unchecked的。

那麼你應該怎麼處理這些討厭的unchecked的異常呢?你可以在它們可能出現的方法中截獲異常,但這種方法有很大的偶然性。這麼做可以解決一個問題,但是它會使其它unchecked的異常中斷代碼的其它部分。我們應該感謝ThreadGroup類提供的一個很好的辦法:

public class ApplicationLoader extends ThreadGroup
{
     private ApplicationLoader()
     {
          super("ApplicationLoader");
     }
     public static void main(String[] args)
     {
          Runnable appStarter = new Runnable()
          {
               public void run()
               {
                    //invoke your application
                    (i.e. MySystem.main(args)}
          }
          new Thread(new ApplicationLoader(), 
appStarter).start();
     }

     //We overload this method from our parent
     //ThreadGroup , which will make sure that it
     //gets called when it needs to be.  This is 
     //where the magic occurs.
public void uncaughtException(Thread thread, Throwable exception)
     {
          //Handle the error/exception.
          //Typical operations might be displaying a
          //useful dialog, writing to an event log, etc.
     }

 

這個方法給我們的編程帶來了很大的改變。想想吧,過去當你在你的GUI中執行一個操作時,如果出現了一個unchecked的異常,你的GUI通常處於一種不正常的狀態(對話框仍然打開、按鈕不能激活,指針處於錯誤狀態),但是運用這種方法,你就可以使GUI回覆到其正常狀態,通知用戶所出現的錯誤,對此你會感覺良好,因爲你編寫了一個高質量的應用程序。

但這種技巧不僅僅用於GUI。運用過多資源的服務器應用程序可以用這種方法在全局釋放資源,通常避免VM進入一種不穩定的狀態。儘早並儘可能多地截獲錯誤、以明智的方法來處理它們,這是一個偉大的程序員和一個普通的程序員之間的不同。由於你已經閱讀了本文,你想成爲哪種程序員就是顯而易見的了。

 

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