10.3 異常處理語法
為了方便程序員進行異常的處理,在Java語言中創建了一套語法,這些語法主要分為以下幾個部分:
1、拋出異常
當程序運行時,如果發現異常的情況,通過生成對應的異常對象,並將該異常對象傳遞給Java的運行時系統,使得系統中包含該異常信息,這樣的過程被稱作拋出異常。
拋出異常是整個異常處理機制的起點,也是異常的發源地,一般出現在項目底層的代碼中。
2、聲明異常
當一個方法在執行時,除了能夠完成正常的功能以外,還可以出現一些異常情況,為了提醒調用該方法的程序員注意處理這些異常情況,需要在方法的聲明中將這些異常聲明出來,這就是聲明異常。
聲明異常的語法使得異常處理更加容易進行實現。
3、捕獲異常及異常處理
當異常被拋出以後,如果不進行處理,則異常會在方法調用過程中一直進行傳遞,直到最後一個方法,在J2SE中也就是main方法,最終將顯示在控制台。
在實際項目中,當異常被拋出以後,需要首先捕獲到該異常,按照異常的種類不同,分別進行處理。
4、聲明自定義異常類
雖然在JDK API中提供了幾百個異常類,但是這些異常所代表的還只是常見的異常情況,在實際使用時還是無法代表所有的異常情況,所以Java語言運行聲明自定義的異常類,使用這些自定義的異常類來代表實際項目中JDK API無法代表的異常情況。
下面依次詳細介紹一下這些語法的相關規則。
10.3.1 拋出異常
在書寫項目中相關的底層基礎代碼時,相關的方法除了實現應該實現的功能以外,還需要考慮到各種異常情況,如果出現該代碼所在的方法無法處理的異常情況時,則應該在該方法內部拋出對應類型的異常時,使得整個方法的邏輯比較嚴謹。
例如,下面是一個實現將十進制數字轉換為二進制或8進制字符串的方法:
/**
* 將自然數轉換為二進制或八進制字符串
* @param value 需要轉換的自然數
* @param radix 基數,只能取2或8
* @return 轉換後的字符串
*/
public static String toString(int value,int radix){
if(value == 0){
return "0";
}
StringBuffer s = new StringBuffer();
int temp; //余數
while(value != 0){ //未轉換結束
temp = value % radix; //取余數
s.insert(0,temp); //添加到字符串緩沖區
value /= radix; //去掉余數
}
return s.toString();
}
在該方法中使用除n取余的方法,將參數value轉換為對應的字符串,當在main方法中以書寫如下代碼時:
System.out.println(toString(12,2));
則程序的運行結果是:
1100
這樣在正常的情況下,程序獲得了正確的結果,但是該方法由於邏輯的限制,只能實現將“自然數”轉換為“二進制或八進制”字符串,如果在其它程序員誤傳入非法的參數時,則程序會獲得不正常的結果,例如書寫如下調用的代碼時:
System.out.println(toString(12,16));
則程序的運行結果是:
12
這個結果在轉換的邏輯上就是錯誤的。這樣就因為其它程序員誤傳入非法參數而出現了錯誤的結果。如果該方法作為實際項目的一個邏輯存在,則會由於該方法的問題導致後續其它的功能也發生錯誤,這是每個程序員都不希望看到的。
所以該方法雖然在功能上達到了要求,但是邏輯還是不嚴謹的,還需要在其它程序員調用該方法時傳入非法參數這樣的異常情況時,將這種異常報告出來,這就需要拋出異常的的代碼了。
拋出異常的語法格式為:
throw 異常對象;
例如:
throw new NullPointerException();
或
IllegalArgumentException e = new IllegalArgumentException();
throw e;
該代碼書寫在方法或構造方法的內部。該語法中,使用throw關鍵字,後續為代表對應異常情況的異常類類型的對象。當系統執行到該代碼時,將中止當前方法的執行,而直接返回到調用該方法的位置。所以在該代碼下面不能直接書寫其它的代碼,因為這些代碼將永遠無法執行到。例如:
throw new NullPointerException();
int n = 10; //語法錯誤,該代碼無法到達
按照該語法,則上面的轉換方法改造以後的代碼如下:
/**
* 將自然數轉換為二進制或八進制字符串
* @param value 需要轉換的自然數
* @param radix 基數,只能取2或8
* @return 轉換後的字符串
*/
public static String toString(int value,int radix){
//判斷異常的代碼
if(value <0){
throw new IllegalArgumentException("需要轉換的數字不是自然數!");
}
if(radix != 2 && radix != 8){
throw new IllegalArgumentException("進制參數非法");
}
if(value == 0){
return "0";
}
StringBuffer s = new StringBuffer();
int temp; //余數
while(value != 0){ //未轉換結束
temp = value % radix; //取余數
s.insert(0,temp); //添加到字符串緩沖區
value /= radix; //去掉余數
}
return s.toString();
}
這裡,當value的值小於0時,則拋出非法參數異常,當radix的值不是2或8時,則拋出非法參數異常。
這樣在執行如下代碼:
System.out.println(toString(12,2));
System.out.println(toString(12,16));
則程序的執行結果是:
1100
Exception in thread "main" java.lang.IllegalArgumentException: 進制參數非法
at ThrowException.toString(ThrowException.java:22)
at ThrowException.main(ThrowException.java:7)
這裡當參數符合要求時,則輸出正確結果1100,如果參數不合法,則拋出異常,由於異常沒有得到處理,則將終止程序的執行,則控制台輸出異常的信息,並顯示異常的類型以及異常出現的位置。
這樣,就通過拋出異常的語法,使得該方法的邏輯比較嚴謹,在方法的參數不合法,即出現異常情況時,將這個異常報告出來,使得該方法不會出現錯誤的結果。
另外,拋出的異常將傳遞給運行時系統,這樣就將這種異常的情況傳遞出來,提醒其它的結構進行處理。
10.3.2 聲明異常
異常雖然被拋出了,但是由於拋出異常的代碼是在方法或構造方法的內部的,在調用方法或構造方法時一般是無法看到方法或構造方法的源代碼的,這樣調用的程序員就無法知道該方法或構造方法將出現怎樣的異常情況,所以需要有一種語法,可以使得調用的程序員可以看到被調用的結構可能出現的異常情況,這就是聲明異常的語法。
聲明異常的語法類似於藥品上的副作用說明,在患者服用藥品時,知道藥品的正常功能,但是無法詳細了解藥品的成分以及每種成分的含量(類似於源代碼),但是在藥品的說明上都有副作用的說明,例如過敏者不能服用等,這些和聲明異常的語法在功能上是類似。
聲明異常的語法格式為:
throws 異常類名
例如:
public static void test(int n) throws IllegalArgumentException,IOException
public Test()throws IllegalArgumentException
該語法使用在方法和構造方法的聲明以後,在throws關鍵字以後,書寫該方法或構造方法可能出現的異常,在這裡需要書寫異常類的類名,如果有多個,則使用逗號分隔這些異常類名即可。
這裡需要注意的是:
1、這些異常必須是該方法內部可能拋出的異常
2、異常類名之間沒有順序
3、屬於RuntimeException子類的異常可以不書寫在throws語句以後,但是另外一類異常如果可能拋出則必須聲明在throws語句之後
通過在對應的方法或構造方法聲明中書寫throws語句,使得調用該方法或構造方法的程序員可以在調用時看到對應結構可能出現的異常情況,從而提示對於這些異常情況進行處理,從而增強程序的健壯性。
而且即使在程序由於未處理對應的異常而導致程序在運行時出現錯誤時,也可以使程序員可以通過對應的提示獲得錯誤的原因,並指導程序員進行邏輯的修正,這樣都可以提高程序編寫時的效率,也可以使程序員更加容易的編寫出邏輯嚴謹的代碼,從而增加項目的質量,提高程序的穩定性。
但是聲明異常以後,異常還是存在的,異常還沒有獲得處理,在異常體系中最重要的還是捕獲到異常,然後針對異常的類型不同作出對應的處理。