異常 異常指的是程式中的不正常現象,一般異常都是由第三方數據的使用造成的。java中每種異常現象都會有一個對應的異常類。java對異常的處理方式就是終止程式。異常機制其實是為了幫助我們找到程式中的問題。異常指的並不是語法錯誤,語法錯了,編譯不通過,不會產生位元組碼文件,根本不能運行。 異常體系 jav ...
異常
異常指的是程式中的不正常現象,一般異常都是由第三方數據的使用造成的。java中每種異常現象都會有一個對應的異常類。java對異常的處理方式就是終止程式。異常機制其實是為了幫助我們找到程式中的問題。異常指的並不是語法錯誤,語法錯了,編譯不通過,不會產生位元組碼文件,根本不能運行。
異常體系
java將程式中遇到的每一種異常現象都封裝成一個對應的異常類。然後將眾多的異常抽取成一個異常體系。而整個異常系統又分為: 錯誤 和 異常兩種現象。
- java.lang.Throwable:異常體系的頂層父類。其下有兩個子類:
- java.lang.Error: 錯誤體系的頂層父類。嚴重的錯誤Error,無法處理,只能預先避免,好比絕症。
- 比如開闢數組空間的個數過多,導致記憶體不夠使用。這不是代碼的問題,而是硬體不足造成的。
- java.lang.Exception:異常體系中的頂層父類。程式中的異常就是指java.lang.Exception。
- 程式中一旦產生了異常的現象,程式開發人員可以通過代碼糾正(就好比生活中身體出現異常,可以通過藥物或其他方式進行治療)。異常是必須要處理的(好比發燒、感冒、闌尾炎)。
小結
Throwable是異常體系的根類。針對於程式中的異常,分為:錯誤(Error)和異常(Exception)。
Error:無法處理,儘量避免。
Exception:必須處理。
異常的產生過程解析
當我們操作了數組不存在的下標時,程式會產生一個數組索引越界異常ArrayIndexOfBoundsException。我們通過圖解來解析下異常產生的過程。
步驟
- 創建一個數組的工具類,類中定義靜態方法getElement(),通過提供的數組和下標獲取對應的元素。
- 創建測試類,在類中定義數組,開闢空間個數3。
- 通過數組工具類名調用獲取數組元素的方法,並傳遞創建的數組和4下標。
- 運行程式,查看結果。
實現
工具類
public class ArrayTools {
// 對給定的數組通過給定的角標獲取元素。
public static int getElement( int[] arr, int index ) {
int element = arr[index];
return element;
}
}
測試類
public class ExceptionDemo {
public static void main(String[] args) {
int[] arr = { 34, 12, 67 };
int num = ArrayTools.getElement(arr, 4)
System.out.println("num = " + num);
System.out.println("over");
}
}
上述程式執行過程圖解:
小結
當程式中的數據產生異常之後,JVM會識別當前異常。然後將異常的信息進行封裝,拋給程式的調用者,讓調用者基於獲取的異常信息進行處理。而如果沒有對異常進行處理,則異常最後會由JVM進行處理。JVM處理的方式就是終止程式,並將異常的信息列印到控制台。
異常分類和處理
目標
程式中需要開發人員處理的異常指的是Exception,這類異常一旦出現,我們就要對代碼進行更正,修複程式。
異常(Exception)的分類:分為 編譯時期異常 和 運行時期異常。
- 編譯時期異常:在編譯時期,就會檢查。如果沒有處理異常,則編譯失敗。( 如日期格式化異常 )
- Exception :編譯時期異常頂層父類。除特殊的子類外,其下所有子類都屬於編譯時期異常類。
- 運行時期異常:在運行時期,檢查異常。運行中發現異常則程式停止運行。編譯時期,不會被編譯器檢測。
- RuntimeException :Exception的一個特殊子類,運行時期異常頂層父類。其下的所有子類都屬於運行時期的異常類。如:下標越界。
- 異常的處理
- 編譯時期異常:編譯時就會編譯報錯,因此必需要處理。只有處理之後才能編譯成功,產生class文件。然後才能夠讓程式運行。
- 運行時期異常:編譯時期不會檢查,運行時期檢測。如果運行時真的出現了異常現象JVM會結束程式。針對於運行時期異常:可以處理,也可以不用處理,一般不處理。
步驟
- 在演示異常的類中創建意思日期字元串。
- 創建DateFormat對象,並調用parse()方法解析日期字元串(編譯異常)
- 對比分析編譯時期和運行時期異常類。
實現
public class ExceptionDemo {
public static void main(String[] args) {
int[] arr = { 34, 12, 67 };
/*
運行時期的異常,只有在運行時才會檢測。編譯時期不會檢測。
*/
int num = ArrayTools.getElement(arr, 4);
System.out.println("num = " + num);
// 創建日期字元串
String time = "2018-12-12";
// 創建DateFormat對象,解析日期字元串
DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
/*
調用parse()方法,解析日期字元串。
當前方法上有一個編譯時期的異常,針對於編譯時期異常一定要進行處理。
否則編譯會報錯。
*/
Date parse = df.parse(time);
System.out.println("parse = " + parse);
System.out.println("over");
}
}
小結
異常分為
編譯時期異常 : 頂層父類Exception,編譯時期檢測,必須要處理的異常。
運行時期異常 : 頂層父類RuntimeException,運行時期檢測,選擇性處理的異常。一般不處理。
異常的處理
Java異常處理的五個關鍵字:try、catch、finally、throw、throws
拋出異常throw
方法上經常要接收調用者傳遞的數據,而方法本身對於傳遞的數據通常會有範圍的限定,超出範圍即為不合法的數據。因此在程式開發時,通常需要對方法上傳遞的參數進行合法性的判斷。如果傳遞的數據不合法,我們則需要將數據非法(異常)的具體信息告知給方法的調用者。就好像生活中看醫生,如果身體出現了異常的現象,醫生會告訴我們具體的病情一樣的道理。
在java中如果需要將數據異常的信息告訴給方法的調用者知道,則需要使用throw關鍵字 。代碼體現就是將異常信息進行封裝,然後使用throw關鍵字拋出給調用者。
- throw關鍵字:用來拋出一個異常對象,將這個異常對象傳遞給調用者,並結束當前方法的執行。步驟:
- 創建一個異常對象。封裝異常的一些提示信息( 信息可以自己編寫 )。
- 通過throw關鍵字,將這個封裝異常信息的對象告知給調用者。
使用格式:
throw new 異常類名(參數);
例如:
throw new NullPointerException("要訪問的arr數組不存在");
throw new ArrayIndexOutOfBoundsException("該索引在數組中不存在,已超出範圍");
註意:異常在拋出時可以分為兩種情況,即:拋出 編譯時期異常 或者 運行時期異常。並且拋出的異常對象必須是異常體系所屬的類。
學習完拋出異常的格式後,我們通過下麵程式演示下throw的使用。
步驟
- 定義getElement()方法,傳遞int數組和下標。
- 使用if判斷,傳遞的下標數據是否合法,如果不合法則拋出下標越界異常並提示異常信息。
- 實現功能,通過下標獲取數組中下標對應的元素。
- 調用方法,查看結果。
實現
public class ThrowDemo {
public static void main(String[] args) {
//創建一個數組
int[] arr = {2,4,52,2};
//根據索引找對應的元素
int index = 4;
int element = getElement(arr, index);
System.out.println(element);
System.out.println("over");
}
/*
* 根據 索引找到數組中對應的元素
*/
public static int getElement( int[] arr,int index ){
//判斷 索引是否越界
if( index < 0 || index > arr.length - 1 ) {
/*
判斷條件如果滿足,當執行完throw拋出異常對象後,方法已經無法繼續運算。
這時就會結束當前方法的執行,並將異常告知給調用者。這時就需要通過異常來解決。
*/
throw new ArrayIndexOutOfBoundsException("哥們,下標越界了~~~");
}
int element = arr[index];
return element;
}
}
小結
程式中如果產生了問題,需要使用throw關鍵字,將描述問題的類即異常進行拋出,也就是將問題返回給該方法的調用者。 格式:
throw new 異常類("異常信息!");
使用throw關鍵字拋出的異常對象,必須是屬於異常體系的類對象。
註意:throw語句下麵,不能寫其他語句,否則會因為無法被執行而導致程式編譯報錯。
那麼對於調用者來說,該怎麼處理呢?基於運行時期異常,一般是不處理。而針對於編譯時期異常,一種是進行捕獲處理,另一種就是繼續將問題聲明出去,使用throws聲明處理。
Objects非空判斷
還記得我們學習過一個類Objects嗎,曾經提到過它由一些靜態的實用方法組成,這些方法是null-save(空指針安全的)或null-tolerant(容忍空指針的),那麼在它的源碼中,將對象為null的值,進行了拋出異常操作。
- public static
T requireNonNull(T obj):查看指定引用對象不是null。
查看源碼發現這裡對為null的進行了拋出異常操作:
public static <T> T requireNonNull( T obj ) {
if ( obj == null )
throw new NullPointerException();
return obj;
}
步驟
- 定義getLength()方法,接收String類型數據,計算其長度並列印。
- 對傳遞的字元串數據進行合法性的判斷,判斷是否為空,如果為空則拋出空指針異常。
- 先使用傳統的if判斷,然後使用Object類中的requireNonNull()方法進行操作。
- 對比兩種操作方式的區別。
實現
public static void getLength( String str ) {
// if判斷傳遞的字元串數據是否合法(為null)
/*if( str == null ) {
throw new NullPointerException("字元串不能為null");
}*/
// Objects靜態方法requireNonNull()方法進行判斷
Objects.requireNonNull( str ,"字元串不能為null");
System.out.println(str + "長度為:" + str.length() );
}
小結
對傳遞的引用類型數據,一般都需要做控制針的判斷。Objects類中的requireNonNull()方法是專門用來判斷引用類型的參數是否為空的。
聲明異常 throws
throw關鍵字拋出的異常分為編譯時期異常 和 運行時期異常。針對於運行時期的異常可以不用作任何的操作處理。但如果拋出的是編譯時期的異常,則必須要進行處理。否則編譯報錯,程式無法運行。而對編譯時期異常的處理方式主要分為: 異常聲明 和 異常捕獲。
- 聲明異常:將異常標識出來,報告給程式的使用者。讓程式的使用者在程式的編譯時期即可發現異常信息。
- 例如生活中,超市售賣商品,有些商品快過期了,超市會在快過期的商品上貼上標簽。讓顧客在買商品時就能看到商品的異常信息。
- throws關鍵字的作用就是在方法上進行異常的聲明,用於表示當前方法不處理異常,而是提醒該方法的調用者來處理異常( 繼續拋出異常 )。
聲明異常格式:
訪問許可權修飾符 返回值類型 方法名(參數) throws 異常類名1 , 異常類名2…{ }
註意:如果方法中拋出多個編譯時期異常,也可以只聲明多個異常的父類異常。
步驟
演示方法異常的聲明。
- 定義read( String path )方法。
- 對傳遞path變數進行判斷
- 判斷是否為null,為null則拋出空指針異常。(運行異常)
- 判斷path路徑地址是否為"a.txt",如果不是則拋出FileNotFoundException文件不存在異常(編譯異常)
- 判斷path路徑地址是否為"b.txt" , 如果不是則拋出IOException異常對象(編譯時期異常)
- 針對編譯時期異常進行聲明處理。
- 調用read()方法,並將main()方法被動接受到的異常繼續聲明到main()方法上。
實現
public class ThrowsDemo {
public static void main(String[] args) throws FileNotFoundException, IOException {
read("a.txt");
}
public static void read(String path) throws FileNotFoundException, IOException {
if (!path.equals("a.txt")) {//如果不是 a.txt這個文件
// 我假設 如果不是 a.txt 認為 該文件不存在 是一個錯誤 也就是異常 throw
throw new FileNotFoundException("文件不存在");
}
if (!path.equals("b.txt")) {
throw new IOException();
}
}
}
小結
如果通過throw關鍵字拋出的編譯時期的異常,那麼就必須要對異常進行處理 , 聲明異常就是對編譯時期異常的一種處理方式:將程式的調用者在編譯時期就可以看到異常信息。需要使用throws關鍵字對異常進行聲明:
訪問許可權修飾符 返回值類型 方法名(參數) throws 異常類名1, 異常類名2...{}
註意:
- throws關鍵字只能用在方法的聲明處。
- throws聲明的類必須是異常體系中的類。
- 如果方法中拋出多個編譯時期異常,那麼也必須在方法上繼續聲明拋出多個異常,或多個異常的父類異常。
- 哪個方法調用了聲明異常的方法,那麼當前方法就會被動接受被調用方法上的異常。
捕獲異常try…catch
使用異常的聲明時,如果方法中真的出了現異常現象,那麼JVM就會將程式終止。造成的後果是後續的代碼無法繼續正常的執行。而如果希望即使出現了異常的現象,也能讓後續的代碼繼續執行,可以使用異常的另外一種處理方式:捕獲異常。
在java中使用:try-catch語句捕獲異常。
- 捕獲異常:對異常語句,針對性進行捕獲,捕獲到異常信息後,可以對捕獲的異常進行自定義方式的處理。
- 提示:JVM對異常的預設處理方式就是終止程式的運行。
- 捕獲異常自定義處理的方式,Throwable中的常用方法:
- public void printStackTrace(): 列印異常的詳細信息。
包含了異常的類型,異常的原因,異常出現的位置,在開發和調試階段,都得使用printStackTrace。 - public String getMessage() : 獲取發生異常的原因。提示給用戶的時候,就提示錯誤原因。
- public void printStackTrace(): 列印異常的詳細信息。
捕獲異常語法如下:
try{
編寫可能會出現異常的代碼
} catch ( 異常類型 e ){
處理異常的代碼
//記錄日誌/列印異常信息/繼續拋出異常
}
/*
try:該代碼塊中編寫可能產生異常的代碼。嘗試運行程式。
catch:用來捕獲程式中產生的異常,並實現對捕獲到的異常進行處理。
異常類型 e:用來接收throw關鍵字拋出的異常對象(也就是異常的信息,因為異常對象中封裝了異常的信息)
*/
註意:try 和 catch都不能單獨使用,必須連用。
步驟
演示使用try-catch語句捕獲異常。
- 定義read( String path )方法。
- 對傳遞path變數進行判斷
- 判斷path路徑地址是否為"a.txt",如果不是則拋出FileNotFoundException文件不存在異常(編譯異常)
- 針對編譯時期異常使用try-catch語句進行捕獲處理。
- 調用read()方法。
實現
public class TryCatchDemo {
public static void main(String[] args) {
// 調用方法 如果方法是聲明處理的異常,此處可以對方法進行捕獲處理。
read("b.txt");
System.out.println("over");
}
// 演示捕獲 異常
public static void read(String path) {
//如果不是 a.txt這個文件
if (!path.equals("a.txt")) {
// 對異常進行捕獲處理
try {
throw new FileNotFoundException("文件不存在");
}catch (FileNotFoundException e ) {
// 自定義處理異常,輸出列印異常被捕獲
System.out.println("異常被抓住了!!!");
}
}
// 列印傳遞的參數
System.out.println("path = " + path );
}
}
小結
針對於程式中的編譯時期異常,除了聲明處理之外,也可以使用捕獲處理。
聲明處理:遇到異常JVM會終止程式的運行。
捕獲處理:遇到異常之後,可以自定義對異常處理。不用結束程式。
try{
可能發生異常的代碼;
}catch( 異常類型 e ) {
對捕獲的異常進行自定義的處理;
}
註意: try-catch 不能單獨使用。
提示:如果方法上的異常是聲明處理的,那麼調用異常方法的方法就會被動接收到異常。此時可以使用聲明的方式繼續將異常聲明出去,也可以使用try-catch語句進行捕獲。
finally 代碼塊
在使用try-catch代碼塊處理異常時,有可能發生異常的代碼是書寫在try代碼塊中。而在異常代碼的下麵,有時還會有其他代碼需要執行。但是一旦真有異常產生,程式會跳轉到catch代碼塊中執行代碼。那麼異常代碼後續的代碼是無法執行的。而如果異常語句下麵的代碼無論是否有異常產生都需要執行,則可以使用finally代碼塊完成。
finally代碼塊:在finally代碼塊中存放的代碼都是一定會被執行的。
當我們在try語句塊中打開了一些物理資源(磁碟文件/網路連接/資料庫連接等),我們都得在使用完之後,最終關閉打開的資源。
finally的語法:
try{
有可能發生異常的代碼;
} catch( 異常類型 e ) {
自定義處理異常;
} finally {
無論是否有異常產生,都需要執行的代碼;
}
註意:finally不能單獨使用。
我們之後學習的IO流中,當打開了一個關聯文件的資源,最後程式不管結果如何,都需要把這個資源關閉掉。
步驟
演示finally代碼塊。
- 定義read( String path )方法。
- 對傳遞path變數進行判斷
- 判斷path路徑地址是否為"a.txt",如果不是則拋出FileNotFoundException文件不存在異常(編譯異常)
- 針對編譯時期異常使用throws進行聲明處理。
- 調用read()方法,並捕獲處理此方法。
- 在read()方法下麵,寫一個一定要執行的輸出語句。
- 傳遞異常數據,產生異常。查看輸出語句是否會被執行。
- 將一定要執行的輸出語句書寫到finally代碼塊中再次運行程式。查看結果。
實現
public class Demo {
public static void main(String[] args) {
try {
readFile("b.txt");
// 無論是否有異常產生都需要執行的代碼,寫在finally代碼塊中
//System.out.println("無論是否有異常產生我都需要執行...");
} catch ( FileNotFoundException e ) {
// 表示異常被抓住並且已經處理了
System.out.println("異常被抓住了..");
// 結束當前JVM,此時finally語句不會執行
// System.exit(0); // 開發中一般不會使用
} finally {
// 無論是否有異常產生都需要執行的代碼,寫在finally代碼塊中
System.out.println("無論是否有異常產生我都需要執行...");
}
}
// 演示finally代碼塊的使用
public static void readFile ( String file ) throws FileNotFoundException {
if( !file.equals("a.txt") ) { // 如果不是a.txt文件
// 假設如果不是a.txt文件,則認為該文件不存在,拋出對應的異常
throw new FileNotFoundException("文件不存在!");
}
}
}
小結
finally代碼塊是用來書寫無論是否發生異常都需要執行的代碼語句。只有在try或者catch中調用退出JVM的相關方法,此時finally才不會執行,否則finally永遠會執行。
finally代碼塊註意事項
因為finally代碼塊中的代碼一定會被執行,所以一般不會將需要返回結果的代碼寫在finally代碼塊中。因為會永遠返回finally代碼塊中的結果。要儘量避免類似情況的發生。
步驟
- 定義getA()方法,返回int類型。
- 在方法內部定義變數 int a = 10;
- 定義try-catch-finally代碼塊
- 在try代碼塊中直接返回變數 a;
- 在finally代碼塊中給變數a重新賦值,返回在返回。
- 調用getA()方法。獲取返回的結果並查看。
實現
public class Demo {
public static void main(String[] args) {
// 調用方法,獲取返回值
int i = gatA();
System.out.println("i = " + i); // 100
}
// 演示捕獲 異常
public static int gatA() {
// 定義變數 a
int a = 10;
try{
return a;
}catch ( Exception e ) {
System.out.println(e);
} finally {
a = 100;
return a;
}
}
}
小結
如果finally代碼塊中有return語句,那麼一定會返回finally代碼塊中的結果。儘量避免類型情況的發生。
自定義異常
自定義異常類概述
在java中,一個異常類表示了一種異常現象。而這些異常類都JDK內部定義好的。但是實際開發中,也會出現很多異常現象,並且這些異常現象是JDK中沒有定義的。此時我們可以根據自己業務的異常情況來自定義異常類。
- 自定義異常類 : 在開發中根據自己業務的異常情況自定義的異常類。
- 自定義異常類註意事項 :
- java中規定,只有Throwable異常體系的類,才能進行拋出或聲明等異常處理。
- 所以自定義的異常類必須繼承異常類體系。
- 自定義一個編譯期異常:自定義類 並繼承於java.lang.Exception。
- 自定義一個運行時期的異常類:自定義類 並繼承於java.lang.RuntimeException。
- java中規定,只有Throwable異常體系的類,才能進行拋出或聲明等異常處理。
自定義異常類格式
訪問許可權修飾符 class 異常類名 extends Exception | RuntimeException {
// 空參構造
public 異常類名(){}
// 異常信息提示構造 使用字元串數據提示異常的具體信息
public 異常類名( String message ){
super( message );
}
}
步驟
定義一個註冊異常的編譯時期異常類。
- 自定義LoginException類。
- 繼承Exception類。
- 在類中定義空參構造 和 異常信息提示構造。
實現
// 業務邏輯異常
public class LoginException extends Exception {
/**
* 空參構造
*/
public LoginException() {
}
/**
*
* @param message 表示異常提示
*/
public LoginException(String message) {
super(message);
}
}
小結
當程式中出現異常現象時,我們需要將異常信息封裝,然後拋出給程式的調用者知道。代碼體現就是創建異常現象對應的異常類對象,然後使用throw關鍵字拋出。而如果程式中的異常現象沒有對應的異常類時,我們可以根據項目情況自己定義異常類。而java中規定,只有屬於異常體系的類才能使用處理異常的關鍵字進行處理。所以自定義的異常類要繼承異常體系類。
如果希望是編譯時期異常則繼承:Exception類。
如果希望是運行時期異常則繼承:RuntimeException類。
自定義的異常類中需要提供一個空參構造,一個異常信息提示的構造方法。
自定義異常的練習
步驟
要求:我們模擬登陸操作,如果用戶名已存在,則拋出異常並提示:親,該用戶名已經被註冊。
- 定義一個靜態的成員字元串數組,併在數組中聲明幾個賬號,用於模擬資料庫。
- 定義checkUsername( String name )方法,判斷註冊的賬號是否存在
- 遍歷取出模擬資料庫數組中的數據
- 使用資料庫中已經存在的賬號和註冊的賬號進行比較。如果用戶名已存在,則拋出異常並提示:親,該用戶名已經被註冊。
實現
public class Demo {
// 模擬資料庫已經存在的賬號
private static String[] names = {"zhangSan","liSi","wangWu"};
public static void main(String[] args) {
// 調用方法
try{
// 可能出現異常的代碼
checkUsername("liSi");
// 沒有發生異常,則表示註冊成功
System.out.println("賬號註冊成功!!");
}catch ( LoginException e ) {
// 處理異常
e.printStackTrace();
}
}
// 判斷當前賬號是否存在
public static boolean checkUsername ( String unams ) throws LoginException {
// 迴圈資料庫中的所有賬號
for( String name : names ) {
// 將取出的資料庫中的賬號和申請的賬號比價
if( unams.equals( name ) ) {
// 如果進入if說明賬號已經存在,則拋出賬號存在異常
throw new LoginException("賬號已經存在!!");
}
}
// 沒有拋出異常,說明賬號不存在。
return true;
}
}
小結
自定義異常類和JDK中定義好的異常類的使用方式都是一樣的。也可以通過throw關鍵字拋出,通過throws關鍵字聲明,或者通過try-catch代碼塊進行捕獲處理。
3.3 多個異常捕獲擴展
在程式中,異常現象不可能只出現一個。有時一個程式中會出現多個異常現象。多個異常的捕獲,有多種不同的方式。
多個異常多次捕獲多次處理
步驟
- 自定義異常A類,繼承Exception類。
- 自定義異常B類,繼承繼承A類。
- 定義getAException( int a )方法,並對a進行判斷,如果a==0,則拋出A異常。
- 定義getBException( int b )方法,並對b進行判斷,如果b==0,則拋出B異常。
- 調用getAException( int a ),並使用捕獲處理。
- 調用getBException( int b ),並使用捕獲處理。
實現
// 自定義異常A類
public class A extends RuntimeException {
// 空參構造
public A() { }
// 異常提示構造
public A(String message) {
super(message);
}
}
// 自定義異常B類,繼承A類
public class B extends A {
// 空參構造
public B() {}
// 異常提示構造
public B(String message) {
super(message);
}
}
// 演示多個異常的單獨處理
public class Demo {
public static void main(String[] args) {
// 單獨處理A異常
try{
getAException(0);
}catch ( A e ) {
System.out.println("異常被抓住了...");
e.printStackTrace();
}
// 單路處理B異常
try {
getBException(0);
} catch ( B e ) {
System.out.println("異常被抓住了...");
e.printStackTrace();
}
/*
針對於運行時期異常,使用try-catch的方式進行捕獲。
好處在於: 即使有異常發生,後續代碼也可以繼續執行。
*/
System.out.println("後續代碼....");
}
// 定義方法,拋出A類異常
public static void getAException( int a ) {
if( a == 0 ) {
throw new A("不能為0!");
}
}
// 定義方法,拋出B類異常
public static void getBException( int b ) {
if( b == 0 ) {
throw new B("不能為0!");
}
}
}
小結
當程式中有多個異常時,基於需求的需要我們可以對多個異常分別使用try-catch語句進行捕獲處理。
多個異常一次捕獲多次處理
try-catch代碼塊擴展語法:
try{
編寫可能會出現異常的代碼
}catch( 異常類型A e ){ //當try中出現A類型異常,就用該catch來捕獲.
處理異常的代碼
//記錄日誌/列印異常信息/繼續拋出異常
}catch( 異常類型B e ){ //當try中出現B類型異常,就用該catch來捕獲.
處理異常的代碼
//記錄日誌/列印異常信息/繼續拋出異常
}
步驟
- 調用getAException( int a )
- 調用getBException( int b )
- 對兩個異常方法一次進行捕獲
- 使用多個catch代碼塊處理捕獲的多個異常
實現
// 演示多個異常的一次捕獲,多次處理
public class Demo {
public static void main(String[] args) {
// 多個異常一次捕獲,多次處理
try{
getAException(0);
getBException(0);
}catch ( B e ) {
System.out.println("B類異常被抓住了...");
e.printStackTrace();
}catch ( A e ) {
System.out.println("A類異常被抓住了...");
e.printStackTrace();
}
}
// 定義方法,拋出A類異常
public static void getAException( int a ) {
if( a == 0 ) {
throw new A("不能為0!");
}
}
// 定義方法,拋出B類異常
public static void getBException( int b ) {
if( b == 0 ) {
throw new B("不能為0!");
}
}
}
小結
當程式中有多個異常時,基於需求的需要我們可以對多個異常使用try代碼塊一次捕獲,然後使用多個catch語句分別對異常進行處理。
註意:這種異常處理方式,要求多個catch中的異常不能相同,並且若catch中的多個異常之間有子父類異常的關係,那麼子類異常要求在上面的catch處理,父類異常在下麵的catch處理。
多個異常一次捕獲一次處理
步驟
- 調用getAException( int a )
- 調用getBException( int b )
- 對兩個異常方法一次進行捕獲
- 使用一個catch代碼塊處理捕獲的多個異常
實現
// 演示多個異常的一次捕獲,一次處理
public class Demo {
public static void main(String[] args) {
// 多個異常一次捕獲,一次處理
try{
getAException(1);
getBException(0);
}catch ( A e ) {
System.out.println("類異常被抓住了...");
e.printStackTrace();
}
}
// 定義方法,拋出A類異常
public static void getAException( int a ) {
if( a == 0 ) {
throw new A("a不能為0!");
}
}
// 定義方法,拋出B類異常
public static void getBException( int b ) {
if( b == 0 ) {
throw new B("b不能為0!");
}
}
}
小結
當程式中有多個異常時,基於需求的需要我們可以對多個異常使用try代碼塊一次捕獲,然後使用一個catch語句對異常進行處理。
註意:這種異常處理方式,要不catch語句中的異常類型,必須是多個異常的父類類型。能夠接收任意一個被拋出的異常對象。
繼承中異常註意事項
- 如果父類聲明瞭多個異常,子類重寫父類方法時,只能聲明相同的異常或者是他的子集。也可以不聲明
- 父類方法沒有聲明異常,子類重寫父類該方法時也不可拋出異常。此時子類產生該異常,只能捕獲處理,不能聲明拋出
步驟
- 創建父類,在類中定義show( int a , int b )方法.
- 分別對變數 a 和 b進行判斷,如果結果為0,則分別拋出A,B異常。
- 定義子類,重寫父類中的方法。驗證繼承中的異常註意事項。
實現
// 父類
class Fu {
// 父類中的方法
public void show( int a, int b ) throws A, B {
if( a == 0 ) {
throw new A("a不能為0!");
}
if( b == 0 ) {
throw new B("b不能為0!");
}
}
}
class Zi extends Fu {
// 子類重寫父類中的方法
public void show( int a , int b ) throws B {
System.out.println("重寫....");
}
}
小結
繼承中,子類重寫父類方法時,父類沒有聲明異常。子類也不能聲明異常。如果父類上有聲明異常,子類重寫時可以不用聲明,或者聲明父類異常上的子類異常,但是異常的個數不能超過父類聲明的異常個數。
健康的父親,兒子也應該健康。多病的父親,基於進化學,兒子應該比父親健康。