很多程序員不清楚error和exception之間的區別,這區別對于如何正確的處理問題而言非常重要(見附1,“簡要的敘述error和exception”)。就像Mary Campione的“The Java Tutorial”中所寫的:“exception就是在程序執行中所發生的中斷了正常指令流的事件(An exception is an event that occurs during the execution of a program that disrupts the normal flow of instructions.)。”依照美國傳統辭典(American Heritage Dictionary)所解釋的,error就是:“效果或情況背離了可接受的一般法則(The act or an instance of deviating from an accepted code of behavior.)”
背離(deviation)、中斷(disruption),有什么區別呢?讓我們來這樣想:如果你驅車在公路上行駛時有人攔住了你,這就叫做“中斷”。如果車根本就無法發動,那就叫做“背離”。
這與Java有什么關系呢?很多。Java中有一個相當有趣的error和exception的結構。
是的,非常正確:所有使用try{} catch(Exception e){}的代碼塊只能找到你一半的錯誤。但是,是否try并catch Throwable取決于你捕捉它的原因。快速的看一下Error的子類,它們的名字類似VirtualMachineError,ThreadDeath,LinkageError。當你想捕獲這些家伙們的時候,你要確定你需要捕獲它們。因為那些都是很嚴重的錯誤。
但是ClassCastException是一個error嗎?不完全是。ClassCastException或任何類型的exception只是虛擬機(VM,VirtualMachine)讓你知道有問題發生的方式,這說明,開發者產生了一個錯誤,現在有一個機會去修正它。
另一方面,error是虛擬機的問題(通常是這樣,但也可能是操作系統的問題)。引用Java文檔中關于error的說明:“Error是Throwable的子類,它的出現說明出現了嚴重的問題。一般應用程序除非有理由,否則不應該捕捉Error。通常這是非常反常的情況。”
所以,error非常強大,而且但處理它遠比一般開發者想象的要難(當然不是你)。如果你在做一項很簡單的工作的話,你認為有必要去處理error?
首先,記住,error跟exception拋出的方式大體相同的,只有一點不同。就是一個拋出error的方法不需要對此進行聲明(換句話說,這是一個unchecked exception(也被稱做Runtime Exception))。
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();
}
注意,有一些exception是不可控制的(unchecked exception),跟error的表現是一樣的,如:NullPointerException,ClassCastException 和 IndexOutOfBoundsException,它們都是RuntimeException的子類。RuntimeException 和其子類都是unchecked excception。
那應該如何處理這些令人討厭的unchecked exception呢?你可以在可能出現問題的地方catch它們,但這只是一個不完整的解決方法。這樣雖然解決了一個問題,但其余的代碼仍可能被其他unchecked exception所中斷。這里有一個更好的辦法,感謝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 exception被拋出了。并且你的GUI程序常常具有了錯誤的狀態(對話框仍舊開著,按鈕失效了,光標狀態出現錯誤)。但是,使用這個技巧,你可以將你的GUI程序恢復原始狀態并通知用戶出現了錯誤。對自己感覺很棒吧,因為你寫了一個高質量的應用程序。
這個技巧并不只適用于GUI程序。服務器端應用程序可以使用這個技巧來釋放資源,防止虛擬機進入不穩定狀態。較早的捕獲錯誤并聰明的將其處理是好的程序員和普通程序員的區別之一。你已經明白了這些,我知道你想成為哪一類程序員。
關于作者
Josh Street是Bank of America的構架設計師。他主要負責電子商務平臺的開發。
聯系方式是rjstreet@computer.org。
附1
簡要的敘述error和exception
Error和Exception都繼承自Throwable,他們下列不同處:
Exceptions
1.可以是 可被控制(checked) 或 不可控制的(unchecked)
2.表示一個由程序員導致的錯誤
3.應該在應用程序級被處理
Errors
1.總是 不可控制的(unchecked)
2.經常用來用于表示系統錯誤或低層資源的錯誤
3.如何可能的話,應該在系統級被捕捉