文章目錄
- 一 異常的概念與體系結構
- 1.1 什么是異常?
- 1.2 異常的體系結構!
- 1.3 編譯時異常與運行時異常與Error
- 編譯時異常:
- 異常聲明:throws關鍵字
- 運行時異常:
- 什么是Error?
- 二 處理異常
- 2.1 異常的拋出:throw(注意與throws有區別!)
- 2.2 異常的捕獲(具體處理):
- try—catch語句
- 2.3 關于異常的處理方式:
- 2.4 異常處理流程總結:
- 三 自定義異常類
一 異常的概念與體系結構
1.1 什么是異常?
//異常是指代碼中除了語法錯誤之外,出現的問題導致代碼出現不正常行為的狀況稱之為異常!//在java中用異常類來表示異常,因為java的思想是一切皆對象。
比如數組越界,除0,棧溢出:這三種異常:
//數組越界:int array[] = {1,2,3,4,5};System.out.println(array[10]);
結果:
顯示為:ArrayIndexOutOfBoundsException異常(此異常為數組越界異常)
后面是原因: Index 10 out of bounds for length 5
//除0System.out.println(10/0);
結果:
顯示為: ArithmeticException異常(此異常為算術異常)
后面顯示原因: / by zero
1.2 異常的體系結構!
異常種類繁多,為了對不同異常或者錯誤進行很好的分類管理,Java內部維護了一個異常的體系結構:
大體的體系結構:
具體的:
其中RunTimeException以及其子類對應的異常,都稱為運行時異常。
1.3 編譯時異常與運行時異常與Error
編譯時異常:
所謂編譯時異常是指在編譯階段發生的異常,為此我們必須對可能出現的編譯異常進行操作,聲明以便拋出或者直接處理。而不是像對運行時異常那樣,可以既不聲明,也不處理(異常的處理下面會闡述到!)。
異常聲明:throws關鍵字
throws關鍵字處于方法聲明時參數列表之后,當方法中拋出編譯時異常,表示該方法并沒有處理異常,而是交
給方法的調用者來處理。即此關鍵字的作用在于提醒方法的調用者處理異常。
舉例: 克隆對象:
我們必須進行對可能出現的異常進行聲明或者處理!
用throws關鍵字進行聲明:
后面跟上可能出現的異常類:CloneNotSupportedException
運行時異常:
運行時異常是指程序在編譯階段結束后,生成了.class文件,在JVM執行時,出現的異常。
對于可能出現的運行時異常,我們可以不進行聲明或者處理。
比如:數組越界
//數組越界:int array[] = {1,2,3,4,5};System.out.println(array[10]);
什么是Error?
//Error是指java虛擬機無法解決的嚴重問題,比如:JVM內部錯誤,資源耗盡 如:棧溢出
舉例:
public static void func1 (){func1();}public static void main(String[] args) {func1();}
要注意,紅圈的部分其他的是Exception,而此處是Error.
我們是不會用throws聲明Error類及其子類的異常的,因為出現了就沒救(JVM無法解決),無意義。
二 處理異常
當異常出現時,我們可以選擇進行處理,或者什么都不做,交給JVM處理
JVM處理的結果即拋出異常,結束程序!
在Java中,異常處理主要的5個關鍵字:throw、try、catch、?nally、throws。
2.1 異常的拋出:throw(注意與throws有區別!)
異常的拋出用于當程序出現問題時,報告給調用者情況。
舉例:
public class Test {public static void func1 (){func1();}public static void main(String[] args) {//throw關鍵字int a = 10;if(a<20){throw new ArithmeticException("胡亂調用了異常類");}System.out.println(a);}}
我們設定的條件是當a<20時,拋出異常,結果成功。
結果還表明:當拋出異常后,異常后面的代碼不被執行。
2.2 異常的捕獲(具體處理):
異常的捕獲即異常的具體處理,主要有兩種方式:一種是throws聲明,這個在前面講過,不再贅述,另一種則是try—catch捕獲
try—catch語句
try—catch語句的語法格式是:
try{//此處放置要執行的代碼,可以會出現異常}catch (要捕獲的異常類型 e){// 如果try中的代碼拋出異常了,此處catch捕獲時異常類型與try中拋出的異常類型一致時,或者是try中拋出異常的基類// 時,就會被捕獲到 ,對異常就可以正常處理,處理完成后,跳出try-catch結構,繼續執行后序代碼}[catch(要捕獲的異常類型 e){//此處放置處理異常的代碼}finally{//此處放置的代碼,必定會被執行}]//后續代碼://此處的代碼,如果沒出現異常或者出現了異常并處理了,則此處代碼會被執行//若出現了異常但沒有被處理,則此處的代碼不會被執行!注: (1) [] 中的內容可加可不加(2) try中的代碼塊不一定會報異常!
其中finally關鍵字的代碼塊用于回收系統資源,不管是程序退出,還是拋出異常都需要回收資源
比如在打開文件后,需要關閉文件,即回收系統資源。
舉例1 :有多個異常時,try-catch語句能否同時捕獲?
//try—catch語句// int [] array = {1,2,3,4,5};int [] array = null;try{System.out.println(10/0);System.out.println(array.length); //打印數組的長度}catch (NullPointerException e){//空指針異常System.out.println("空指針異常");}catch (ArithmeticException e){// 異常的處理方式System.out.println(e.getMessage()); // 只打印異常信息System.out.println(e); // 打印異常類型:異常信息e.printStackTrace(); // 打印信息最全面}finally {System.out.println("finally中執行的代碼");}System.out.println("后續代碼塊");
結果表明:我們通過try—catch語句只能捕獲一個異常因為: try塊內拋出異常位置之后的代碼將不會被執行
舉例2:
如果多個異常的處理方式是相同的,則簡寫成:
int[] array = null;try {System.out.println(10 / 0);System.out.println(array.length); //打印數組的長度} catch (NullPointerException | ArithmeticException e) {//空指針異常System.out.println(e.getMessage()); //只打印異常信息——/by zeroSystem.out.println(e); // 打印異常類型:異常信息e.printStackTrace(); //打印信息最全面 ——打印異常類型,打印異常信息,還打印異常所在的代碼!} finally {System.out.println("finally中執行的代碼");}System.out.println("后續代碼塊");}
舉例三:
如果異常之間具有父子關系,一定是子類異常在前catch,父類異常在后catch,否則語法錯誤:
2.3 關于異常的處理方式:
2.4 異常處理流程總結:
- 先執行try塊中的代碼
- 如果發現異常,則在catch中判斷是否與catch的異常類型相同,如果相同則執行catch中的代碼,如果不同則將異常向上傳遞給上一層調用者。
- 無論異常是否被處理,finally中的代碼都會被執行(在該方法結束之前執行),但是如果異常并沒有被處理,則后續代碼不會被執行。
- 如果上層調用者依然無法處理異常,則繼續傳遞給上層,直到傳遞到main方法,main方法也無法處理,則交給JVM,最終異常結束程序。
public static void func() {int[] arr = {1, 2, 3};System.out.println(arr[100]);}public static void main(String[] args) {func();System.out.println("after try catch");}
結果表明:顯示了異常的調用棧,且最終after try catch語句沒有被執行!
三 自定義異常類
java中提供的異常類不能代表所有我們在日常開發中遇到的問題,所以我們需要自己定義異常類
舉例:
package demo1;public class PasswordException extends Exception{public PasswordException(String message){super(message);}}
package demo1;public class UserNameException extends Exception{public UserNameException(String message){super(message);}
}
public class Test {private String userName = "admin";private String password = "123456";public void loginInfo(String userName, String password)throws UserNameException,PasswordException{if (! this.userName.equals(userName)) {throw new UserNameException("用戶名錯誤!");}if (! this.password.equals(password)) {throw new PasswordException("用戶名錯誤!");}System.out.println("登陸成功");}public static void main(String[] args) {try {new Test(). loginInfo("admin", "123456");} catch (UserNameException e) {e.printStackTrace();} catch (PasswordException e) {e.printStackTrace();}}
注意事項
自定義異常通常會繼承自 Exception 或者 RuntimeException
繼承自 Exception 的異常默認是受查異常
繼承自 RuntimeException 的異常默認是非受查異常.