在捕獲異常以前,某些代碼必須拋出一個,任何代碼均可能拋出異常:你的代碼,來自其餘人編寫的包中的代碼,例如Java平臺附帶的包或Java運行時環境,不管拋出什麼異常,它老是使用throw
語句拋出。html
你可能已經注意到,Java平臺提供了許多異常類,全部類都是Throwable類的後代,而且全部類都容許程序區分在程序執行期間可能發生的各類類型的異常。java
你還能夠建立本身的異常類來表示你編寫的類中可能出現的問題,實際上,若是你是程序包開發人員,則可能必須建立本身的一組異常類,以容許用戶將程序包中可能發生的錯誤與Java平臺或其餘程序包中發生的錯誤區分開來。程序員
你還能夠建立鏈式異常,有關更多信息,請參閱「鏈式異常」部分。segmentfault
全部方法都使用throw
語句拋出異常,throw語句須要一個參數:一個throwable
對象,Throwable
對象是Throwable
類的任何子類的實例,這是一個throw
語句的例子。api
throw someThrowableObject;
讓咱們看一下上下文中的throw
語句,如下pop
方法取自實現公共堆棧對象的類,該方法從堆棧中刪除頂部元素並返回該對象。數組
public Object pop() { Object obj; if (size == 0) { throw new EmptyStackException(); } obj = objectAt(size - 1); setObjectAt(size - 1, null); size--; return obj; }
pop
方法檢查堆棧上是否有任何元素,若是堆棧爲空(其大小等於0),則pop
實例化一個新的EmptyStackException
對象(java.util
的成員)並拋出它,本章中的建立異常類部分介紹瞭如何建立本身的異常類,如今,你須要記住的是,你只能拋出從java.lang.Throwable
類繼承的對象。oracle
請注意,pop
方法的聲明不包含throws
子句,EmptyStackException
不是已檢查的異常,所以不須要pop
來聲明它可能發生。app
從Throwable
類繼承的對象包括直接後代(直接從Throwable
類繼承的對象)和間接後代(從Throwable
類的子級或孫級繼承的對象),下圖說明了Throwable
類的類層次結構及其最重要的子類,如你所見,Throwable
有兩個直接後代:Error和Exception。函數
當發生Java虛擬機中的動態連接故障或其餘硬故障時,虛擬機拋出Error
,簡單程序一般不會捕獲或拋出Errors
。工具
大多數程序拋出並捕獲從Exception
類派生的對象,Exception
表示發生了問題,但這不是一個嚴重的系統問題,你編寫的大多數程序將拋出並捕獲Exception
而不是Error
。
Java平臺定義了Exception
類的許多後代,這些後表明示可能發生的各類類型的異常。例如,IllegalAccessException
表示沒法找到特定方法,NegativeArraySizeException
表示程序試圖建立負大小的數組。
一個Exception
子類RuntimeException
保留用於指示錯誤使用API的異常,運行時異常的一個示例是NullPointerException
,當方法嘗試經過空引用訪問對象的成員時發生,未經檢查的異常 — 爭議部分討論了爲何大多數應用程序不該拋出運行時異常或RuntimeException
子類。
應用程序一般會經過拋出另外一個異常來響應異常,實際上,第一個異常致使第二個異常,瞭解一個異常什麼時候致使另外一個異常很是有用,鏈式異常有助於程序員執行此操做。
如下是Throwable
中支持鏈式異常的方法和構造函數。
Throwable getCause() Throwable initCause(Throwable) Throwable(String, Throwable) Throwable(Throwable)
initCause
和Throwable
構造函數的Throwable
參數是致使當前異常的異常,getCause
返回致使當前異常的異常,initCause
設置當前異常的緣由。
如下示例顯示如何使用鏈式異常。
try { } catch (IOException e) { throw new SampleException("Other IOException", e); }
在此示例中,捕獲IOException
時,會建立一個新的SampleException
異常,並附加原始緣由,並將異常鏈拋出到下一個更高級別的異常處理程序。
如今讓咱們假設更高級別的異常處理程序想要以本身的格式轉儲堆棧跟蹤。
定義:堆棧跟蹤提供有關當前線程的執行歷史記錄的信息,並列出在發生異常時調用的類和方法的名稱,堆棧跟蹤是一種有用的調試工具,一般在拋出異常時能夠利用它。
如下代碼顯示如何在異常對象上調用getStackTrace
方法。
catch (Exception cause) { StackTraceElement elements[] = cause.getStackTrace(); for (int i = 0, n = elements.length; i < n; i++) { System.err.println(elements[i].getFileName() + ":" + elements[i].getLineNumber() + ">> " + elements[i].getMethodName() + "()"); } }
下一個代碼段記錄catch
塊中發生異常的位置,可是,它不是手動解析堆棧跟蹤並將輸出發送到System.err()
,而是使用java.util.logging包中的日誌記錄工具將輸出發送到文件。
try { Handler handler = new FileHandler("OutFile.log"); Logger.getLogger("").addHandler(handler); } catch (IOException e) { Logger logger = Logger.getLogger("package.name"); StackTraceElement elements[] = e.getStackTrace(); for (int i = 0, n = elements.length; i < n; i++) { logger.log(Level.WARNING, elements[i].getMethodName()); } }
當面對選擇要拋出的異常類型時,你可使用其餘人編寫的異常 — Java平臺提供了許多可使用的異常類 — 或者你能夠編寫本身的異常類,若是你對如下任何問題的回答是確定的,你應該編寫本身的異常類;不然,你可能會使用別人的。
假設你正在編寫鏈表類,該類支持如下方法,其中包括:
objectAt(int n)
— 返回列表中第n
個位置的對象,若是參數小於0或大於列表中當前對象的數量,則引起異常。firstObject()
— 返回列表中的第一個對象,若是列表不包含任何對象,則拋出異常。indexOf(Object o)
— 在列表中搜索指定的Object
並返回其在列表中的位置,若是傳遞給方法的對象不在列表中,則拋出異常。鏈表類能夠拋出多個異常,而且可以經過一個異常處理程序捕獲鏈表所引起的全部異常會很方便,此外,若是你計劃在包中分發鏈表,則應將全部相關代碼打包在一塊兒,所以,鏈表應該提供本身的一組異常類。
下圖說明了鏈表拋出的異常的一個可能的類層次結構。
任何Exception
子類均可以用做LinkedListException
的父類,可是,快速瀏覽這些子類就會發現它們不合適,由於它們太專業化或與LinkedListException
徹底無關,所以,LinkedListException
的父類應該是Exception
。
你編寫的大多數applet和應用程序都會拋出Exception
對象,Error
一般用於系統中嚴重的硬錯誤,例如阻止JVM運行的錯誤。
對於可讀代碼,最好將字符串Exception
附加到從Exception
類繼承(直接或間接)的全部類的名稱。