Java中的異常及其用法
本文主要介紹異常的概念和異常的兩種處理方式。
目錄
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
異常
異常概念
異常 :指的是程式在執行過程中,出現的非正常的情況,最終會導致JVM(Java虛擬機器)的非正常停止。
在Java中,異常本身就是一個類,產生異常就是建立異常物件並丟擲了一個異常物件。Java處理異常就是中斷處理,程式不能繼續跑下去。
注意
異常分類
異常的根類是java.lang.Throwable,其下有兩個子類:java.lang.Error和java.lang.Exception。平常指的異常是Exception。
Throwable體系:
-
Error:嚴重錯誤Error,無法通過處理的錯誤,只能事先避免,好比絕症。
-
Exception:表示異常,異常產生後程序員可以通過程式碼的方式糾正,使程式繼續執行,是必須要處理的。好比感冒、闌尾炎。
Throwable中的常用方法:
-
public void printStackTrace()
包含了異常的型別,異常的原因,還包括異常出現的位置,在開發和除錯階段,都得使用printStackTrace。
-
public String getMessage()
:獲取發生異常的原因。提示給使用者的時候,就提示錯誤原因。
-
public String toString()
:獲取異常的型別和異常描述資訊(不用)。
異常(Exception)分類:
-
編譯時期異常:checked異常。在編譯時期,就會檢查,如果沒有處理異常,則編譯失敗。(如日期格式化異常)
-
執行時期異常:runtime異常。在執行時期,檢查異常.在編譯時期,執行異常不會編譯器檢測(不報錯)。(如數學異常)
注意: 當出現異常的時候,JVM會把異常的內容、原因、位置列印到控制檯,當不知道異常意思或者不知道如何處理的時候,可以把異常類名copy下來拿到API中查。(例如:java.lang.ArrayIndexOutofBoundsException-----陣列越界異常)
異常處理
丟擲異常throw
在java中,提供了一個throw關鍵字,它用來丟擲一個指定的異常物件。用法如下:
-
建立一個異常物件。封裝一些提示資訊(資訊可以自己編寫)。
-
需要將這個異常物件告知給呼叫者。通過關鍵字throw就可以完成。
-
throw用在方法內,用來丟擲一個異常物件,將這個異常物件傳遞到呼叫者處,並結束當前方法的執行。
理解:用throw就是不需要JVM來判斷異常情況,這個異常是我們自己指定的,呼叫者自己編寫異常資訊內容並告訴JVM虛擬機器出現了什麼異常,JVM只需要負責把異常資訊列印到控制檯就可以。
使用格式:
throw new 異常類名(引數);
throw new ArrayIndexOutOfBoundsException("陣列索引越界異常,該索引在陣列中不存在,已超出範圍");
例項:
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將問題描述類即異常進行丟擲,也就是將問題返回給該方法的呼叫者。
對於呼叫者,有兩種處理方式:一種是進行捕獲處理;一種就是繼續將問題宣告出去,使用throws宣告處理
異常處理方式一
宣告異常throws:將問題標識出來,報告給呼叫者。如果方法內通過throw丟擲了編譯時異常,而沒有捕獲處理,那麼必須通過throws進行宣告,讓呼叫者去處理。關鍵字throws運用於方法宣告之上,用於表示當前方法不處理異常,而是提醒該方法的呼叫者來處理異常(丟擲異常).
throws關鍵字:異常處理的第一種方式,交給別人處理
作用:當方法內部丟擲異常物件的時候,那麼我們就必須處理這個異常物件
可以使用throws關鍵字來處理異常物件,會把異常物件宣告丟擲給方法的呼叫者處理(自己不處理,給別人處理),最終交給JVM處理--->中斷處理
使用格式:
修飾符 返回值型別 方法名(引數列表) throws AAAException,BBBException...{
throw new AAAException("產生原因");
throw new AAAException("產生原因");
...
}
注意事項:1. throws關鍵字必須寫在方法宣告處
2. throws關鍵字後邊宣告的異常必須是Exception或者是Exception的子類
3. 方法內部如果丟擲了多個異常物件,那麼throws後邊必須也宣告多個異常, 如果丟擲的多個異常物件有子父類關係,我們就必須的處理宣告的異常
4. 呼叫了一個宣告丟擲異常的方法,我們就必須的處理宣告的異常, 要麼繼續使用throws宣告丟擲,交給方法的呼叫者處理,最終交給JVM;要麼try...catch自己處理異常
理解:說白了第一種異常處理方式就是通過JVM丟擲異常資訊,然後中斷程式,異常還是沒有處理,只是丟擲了,可以提醒呼叫者來處理這個異常資訊。
例項:
package demo1_Exception;
import java.io.FileNotFoundException;
import java.io.IOException;
/*
異常的第一種處理方式:交給別人處理,自己並不處理。
可以使用throws關鍵字來處理異常物件,會把異常物件宣告丟擲給
方法的呼叫者處理(自己不處理,給別人處理),最終交給JVM處理--->中斷處理
*/
public class Test02_ThrowsException {
public static void main(String[] args) throws IOException {
read("C:\\readme.txt");
}
//如果定義功能時有問題發生需要報告給呼叫者。可以通過在方法上使用throws關鍵字進行宣告
private static void read(String s) throws IOException {
//非目標檔案,丟擲異常,在方法上宣告
if(!s.equals("read.txt")){
throw new FileNotFoundException("檔案不存在異常,找不到目標檔案");
}
//throws用於進行異常類的宣告,若該方法可能有多種異常情況產生,
// 那麼在throws後面可以寫多個異常類,用逗號隔開。
if(s.equals("hhreadme.txt")){
throw new IOException("檔案讀取錯誤");
}
}
}
=========================================================
//測試結果
Exception in thread "main" java.io.FileNotFoundException: 檔案不存在異常,找不到目標檔案
at demo1_Exception.Test02_ThrowsException.read(Test02_ThrowsException.java:20)
at demo1_Exception.Test02_ThrowsException.main(Test02_ThrowsException.java:13)
Process finished with exit code 1
異常處理方式二
捕獲異常try...catch:異常處理第二種方式,自己處理。
捕獲異常:Java中對異常有針對性的語句進行捕獲異常,可以出現的異常進行指定方式的處理。
使用格式:
try{
編寫可能會出現異常的程式碼
}catch(異常型別 e){
處理捕獲到的異常
//記錄日誌/列印異常資訊/繼續丟擲異常
}
注意: 1.try可能會丟擲多個異常物件,可以使用多個catch來處理這些異常物件。
2. 如果try產生了異常,那麼就會執行catch中異常處理邏輯,執行完畢catch中處理邏輯,繼續執行try...catch之後的程式碼。
如果try中沒有產生異常,那麼就不會執行catch中的內容,直接執行try...ctach 之後的程式碼。
獲取異常資訊: Throwable類中定義了一些檢視方法
- public String getMessage():獲取異常的描述資訊,原因(提示給使用者的時候,就提示錯誤原因。
- public String toString():獲取異常的型別和異常描述資訊(不用)。
- public void printStackTrace():列印異常的跟蹤棧資訊並輸出到控制檯。
這些檢視方法包含了異常的型別,異常的原因,以及異常出現的位置,在開發和除錯階段,都得使用printStackTrace
例項:
package demo1_Exception;
import java.io.FileNotFoundException;
/*
異常的第二種處理方式:通過try...catch捕獲異常,自己處理
*/
public class Test03_TryCatchException {
public static void main(String[] args) {
//1.下面程式碼可能會出現異常,try..catch捕獲異常
try {
read("C:\\readme.txt");
} catch (FileNotFoundException e) {
//3.捕獲到異常,處理異常
//4.try中丟擲的是什麼型別異常,catch中就定義什麼型別異常
System.out.println(e);
}
System.out.println("over");
}
//2.出現編譯期異常,丟擲異常
private static void read(String s) throws FileNotFoundException {
if(!s.equals("read.txt")){
throw new FileNotFoundException("目標檔案不存在");
}
}
}
finally程式碼塊
概念:有一些特定的程式碼無論異常是否發生,都需要執行。另外,因為異常會引發程式跳轉,導致有些語句執行不到。而finally就是解決這個問題的,在finally程式碼塊中存放的程式碼都是一定會被執行的。(比如在我們之後學習的IO流中,當打開了一個關聯檔案的資源,最後程式不管結果如何,都需要把這個資源關閉掉。 )
注意:finally不能單獨使用。
例項:
package demo1_Exception;
import java.io.FileNotFoundException;
// finally程式碼塊
public class Test04_Finally {
public static void main(String[] args) {
try {
read("readme.txt");
}catch(FileNotFoundException e) {
e.printStackTrace();
}finally{
System.out.println("不管程式怎樣,這裡都會被執行");
}
System.out.println("程式結束");
}
private static void read(String s) throws FileNotFoundException {
if(s.equals("readmehh.txt")){
throw new FileNotFoundException("目標檔案找不到");
}
}
}
=======================================================
//測試結果
不管程式怎樣,這裡都會被執行
程式結束
Process finished with exit code 0
其他異常注意事項
-
執行時異常被丟擲可以不處理。即不捕獲也不宣告丟擲。
-
如果finally有return語句,永遠返回finally中的結果,避免該情況.
-
如果父類丟擲了多個異常,子類重寫父類方法時,丟擲和父類相同的異常或者是父類異常的子類或者不丟擲異常。
-
父類方法沒有丟擲異常,子類重寫父類該方法時也不可丟擲異常。此時子類產生該異常,只能捕獲處理,不能宣告丟擲
自定義異常
概念
為什麼需要自定義異常: 我們說了Java中不同的異常類,分別表示著某一種具體的異常情況,那麼在開發中總是有些異常情況是SUN沒有定義好的,此時我們根據自己業務的異常情況來定義異常類。
自定義異常類:
自定義一個業務邏輯異常:RegisterException. 一個註冊異常類。
如何定義異常類:
1. 自定義一個編譯期異常: 自定義類 並繼承於java.lang.Exception
。
2. 自定義一個執行時期的異常類:自定義類 並繼承於java.lang.RuntimeException
。
用法
首先定義一個註冊異常類:
package demo1_Exception;
//註冊異常
public class Test01_RegisterException extends Exception{
//空參構造
public Test01_RegisterException(){
}
//異常提示
public Test01_RegisterException(String message){
super(message);
}
}
定義一個測試類,模擬註冊操作:
package demo1_Exception;
import java.util.Scanner;
public class Test01 {
public static void main(String[] args) {
String[] str={"張三","王五","李四"};
find_Exception(str);
}
private static void find_Exception(String[] str) {
Scanner sc=new Scanner(System.in);
for (String s : str) {
try{
checkUsername(s,str);
//沒有異常,註冊成功
System.out.println("註冊成功");
}catch (Test01_RegisterException e){
//處理異常
e.printStackTrace();
}
}
}
//判斷當前賬戶是否被註冊
//編譯器異常,聲明後丟擲
private static boolean checkUsername(String s,String[] str) throws Test01_RegisterException {
for (String s1 : str) {
if(s1.equals(s)){
throw new Test01_RegisterException("對不起,親,這個號已經被註冊了");
}
}
return true;
}
}
===========================================================
//測試結果一
請輸入一個賬號:
張三
demo1_Exception.Test01_RegisterException: 對不起,親,這個號已經被註冊了
at demo1_Exception.Test01.checkUsername(Test01.java:32)
at demo1_Exception.Test01.find_Exception(Test01.java:16)
at demo1_Exception.Test01.main(Test01.java:8)
Process finished with exit code 0
===========================================================
//測試結果二
請輸入一個賬號:
趙六
註冊成功
總結
主要分清異常與error的概念,掌握異常處理的兩種方式和自定義異常,後期開發過程會經常用到自定義異常,其他內容瞭解即可。