### 一、什么是異常
異常是程序中一種錯誤,可能是讀取文件錯誤,網絡連接錯誤,也可能是數組越界錯誤,或試圖使用一個沒有被賦值的對象而引起的錯誤。如果由于異常或錯誤使程序操作沒有操作完成,則程序返回一個安全狀態或捕獲異常的處理結果,保證程序的健壯性。
#### (1).異常分類
java語言中,定義了許多的異常類,所有異常類都派生Throwable類,而Throwable類又有兩個子類Error和Exception,分別表示錯誤和異常,
其中Exception又分為運行時異常和非運行時異常。下面為異常的體系結構圖:

#### (2).下面將詳細說明圖中相關異常的區別和聯系
**1.Error和Exception**
Error是程序無法處理的錯誤,通常有內存溢出異常(outofMemoryError),線程終止等,出現這類異常java虛擬機會選擇終止程序。
Exception是程序可處理的異常,它又有兩個分支運行時異常和非運行時異常,出現這類異常是程序需要處理。
**2.運行時異常和非運行時異常**
運行時異常都是RuntimeException類及其子類異常,如NullPointerException、 IndexOutOfBoundsException等,這些異常是不檢查異常,程序中可以選擇捕獲處理,也可以不處理。這些異常一般是由程序邏輯錯誤引 起的,程序應該從邏輯角度盡可能避免這類異常的發生。
非運行時異常是RuntimeException以外的異常,類型上都屬于Exception類及其子類。從程序語法角度講是必須進行處理的異常,
如果不處理,程序就不能編譯通過。如IOException、SQLException等以及用戶自定義的Exception異常。
#### (3).什么時候拋出異常
如果遇到無法處理的問題時,該方法可以選擇拋出異常,至于何時需要在方法中用throws聲明異常,若該方法需要拋出多個異常,則每個異常間用逗號分隔,通常有以下情況需要拋出異常:
1.調用一個已拋出異常的方法,如FileInputStream構造器。
2.程序運行過程錯誤,并用throw拋出一個檢查出的異常。
3.程序出現錯誤。
4.java虛擬機和運行時庫出現的內部異常。
總之一個方法必須聲明所有可能拋出的異常已檢查異常,所有未檢查出的異常要么不可控制,要么就應該避免發生。
#### (4).創建異常
創建異常通常只需要定義派生于Exception類或派生于Exception子類的類。例如定義一個派生于IOException的類,通常定義兩個構造器,一個是默認構造器,一個是帶有詳細描述信息的構造器。如:
~~~
public class MyExcetion extends IOException {
private static final long serialVersionUID = 1L;
public MyExcetion() {
}
public MyExcetion(String message) {
super(message);
}
public MyExcetion(Throwable cause) {
super(cause);
}
public MyExcetion(String message, Throwable cause) {
super(message, cause);
}
}
~~~
### 二、異常處理
程序運行過程中,若出現異常沒有及時處理,則會終止程序的執行。可以用捕獲異常或拋出異常來處理。
若try語句代碼塊出現異常,程序會在catch中尋找匹配的異常,然后調用匹配的異常處理器進行處理。運行過程中程序未找到匹配的異常處理器,程序就會終止。
**(1).try…catch模式**
該模式的定義形式如下
try{
代碼塊;
}catch(Exception e){
}
Catch(Exception e2){ }
匹配的原則是:如果拋出的異常對象屬于catch子句的異常類,或者屬于該異常類的子類,則認為生成的異常對象與catch塊捕獲的異常類型相匹。
**(2).try…catch…finally模式**
該模包含finally,無論程序有無異常發生,且不管try –catch間是否順利執行,都會執行finally語句。
**(3).實例說明:**
1.各模塊的作用
try塊:用于捕獲異常,后面可以跟一個或多個catch,finally可有可無,但必須有一個catch塊。
catch塊:用于處理異常。
finally塊是程序是否有無異常,都需要執行的部分。
但在以下3中特殊情況下不會執行:
A.在finally 語句中發生異常。
B.程序所在線程死亡。
C.在前面的代碼中出現了system.exit()退出程序。
2.當捕獲到一個異常對象之后,你可以調用其getMessage()方法來獲取異常消息,或者調用printStackTrace()方法來打印執行棧的內容
關于getMessage()方法
當你通過new Exception(“message”)或new RuntimeException(“message”)來創建一個異常對象的時候,傳給構造方法的這個參數就是消息,所以,當你捕獲到異常對象之后,可以通過getMessage()方法把消息拿出來!
關于printStackTrace()方法它能把執行棧的內容打印出來
### 三、異常的轉換
所謂異常轉換,即截獲一個異常(往往是checked exception)之后,將其轉換為另外一個異常(往往是unchecked exception)拋出。
比如很多情況下,當我們操作數據庫的時候或操作文件的時候,JDK類庫中的相關操作方法會給我們拋出SQLException或IOException,這些都是checked exception,這些異常一般情況下我們是無法進行處理的,所以,我們需要繼續向上拋出異常,假如我們繼續拋出SQLException或IOException的話,會導致更上層的程序處理起來非常困難(而且也需要在方法中進行聲明)。
因此,大多數情況下,我們在截獲到SQLException或IOException之后,會將它轉換為一種RuntimeException重新拋出,這是非常常見的異常應用技巧!
### 四、異常鏈
所謂異常鏈,即當我們在截獲一個異常,在把它轉換為另外一個異常的時候,記得把原來那個異常對象設置到新的異常對象中即可。我們不妨觀察Throwable類(所有異常類的基類)的構造方法:
public Throwable()
public Throwable(String message)
public Throwable(String message, Throwable cause)
public Throwable(Throwable cause)
我們注意到其中的Throwable類型的參數,它就是用來創建異常鏈的。
下面使用一個實例來說明:
**1.自定義異常類:**
~~~
public class MyException extends RuntimeException {
private static final long serialVersionUID = 1L;
private String errorCode;
public MyException() {
}
public MyException(String message,String errorCode) {
super(message);
this.errorCode=errorCode;
}
//用于創建異常鏈
public MyException(String message,String errorCode,Throwable cause) {
super(message, cause);
this.errorCode=errorCode;
}
public String getErrorCode() {
return errorCode;
}
}
~~~
**2.調用該類**
~~~
public class FileUtils {
public static String readFile(String filePath){
StringBuffer sb=new StringBuffer();
try {
BufferedReader reader=new BufferedReader(new FileReader(filePath));
String line=null;
while((line=reader.readLine())!=null){
sb.append(line);
}
} catch (FileNotFoundException e) {
//將原始對象放到新對象中去
throw new MyException("文件沒有找到!", "1", e);
} catch (IOException e) {
throw new MyException("文件讀取有誤!", "2", e);
}
return sb.toString();
}
}
~~~
### 五、注意事項
1) 必須在 try 之后添加 catch 或 finally 塊。try 塊后可同時接 catch 和 finally 塊,但至少有一個塊。
2) 必須遵循塊順序:若代碼同時使用 catch 和 finally 塊,則必須將 catch 塊放在 try 塊之后。
3) 一個 try 塊可能有多個 catch 塊。若如此,則執行第一個匹配塊
即Java虛擬機會把實際拋出的異常對象依次和各個catch代碼塊聲明的異常類型匹配,如果異常對象為某個異常類型或其子類的實例,就執行這個catch代碼塊,不會再執行其他的 catch代碼塊。
4) 可嵌套 try-catch-finally 結構。
5) 在 try-catch-finally 結構中,可重新拋出異常。
6)多個catch的順序一定要遵循子類在上父類在下的規則。
7)一個方法被重寫,被重寫的方法必須拋出相同的異常或異常的子類。
8)若父類方法拋出多個異常,那子類重寫該方法必須拋出哪些異常的一個子集。