前言
在編程中例外報錯是不可避免的,特別是在學習某個語言初期,看到例外報錯就抓耳撓腮,常常開玩笑說編程1分鐘,改bug1小時,今天就讓我們來看看什么是例外和怎么合理的處理例外吧!
例外與error介紹
下面還是先讓我們來看一下基本概念吧!
? 例外指程式運行程序中出現的非正常現象,例如用戶輸入錯誤、除數為零、需要處理的檔案不存在、陣列下標越界等,例外機制本質就是當程式出現錯誤,程式安全退出的機制,在Java的例外處理機制中,引進了很多用來描述和處理例外的類,稱為例外類,例外類定義中包含了該類例外的資訊和對例外進行處理的方法,
? Java是采用面向物件的方式來處理例外的,處理程序:
- 拋出例外:在執行一個方法時,如果發生例外,則這個方法生成代表該例外的一個物件,停止當前執行路徑,并把例外物件提交給JRE,
- 捕獲例外:JRE得到該例外后,尋找相應的代碼來處理該例外,JRE在方法的呼叫堆疊中查找,從生成例外的方法開始回溯,直到找到相應的例外處理代碼為止,
讓我們來看看前面所講到的例外類究竟是個什么東西!
其實所有的例外物件都是派生于Throwable類的一個實體,如果內置的例外類不能夠滿足需要,還可以創建自己的例外類,所有例外的根類為java.lang.Throwable,看看它的家族長什么樣,

Throwable類下面主要是兩大門派,Error和Exception,
-
Error是程式無法處理的錯誤,表示運行應用程式中較嚴重問題,系統JVM已經處于不可恢復的崩潰狀態中,例如,說記憶體溢位和執行緒死鎖等系統問題,
-
Exception是程式本身能夠處理的例外,
Exception類是所有例外類的父類,其子類對應了各種各樣可能出現的例外事件, 通常Java的例外可分為:
- RuntimeException 運行時例外
- CheckedException 已檢查例外
下面我們來研究研究這兩個例外,
RuntimeException和 CheckedException異同
首先我們先來看看什么是運行時例外,
這類例外通常是由編程錯誤導致的,所以在撰寫程式時,并不要求必須使用例外處理機制來處理這類例外,而是經常需要通過增加“邏輯處理來避免這些例外”,
比如以下常見的幾種例外:
ArithmeticException例外
int b=0;
System.out.println(1/b);
//解決:
if(b!=0){
System.out.println(1/b);
}
NumberFormatException例外
String str = "1234abcf";
System.out.println(Integer.parseInt(str));
//解決:
Pattern p = Pattern.compile("^\\d+$");
Matcher m = p.matcher(str);
if (m.matches()) { // 如果str匹配代表數字的正則運算式,才會轉換
System.out.println(Integer.parseInt(str));
}
ClassCastException例外
Animal a=new Dog();
Cat c=(Cat)a;
//解決:
if (a instanceof Cat) {
Cat c = (Cat) a;
}
這里再補充兩點,方便大家更好的理解java例外的機制和處理程序,
- 在方法拋出例外之后,運行時系統將轉為尋找合適的例外處理器(exception handler),潛在的例外處理器是例外發生時依次存留在呼叫堆疊中的方法的集合,當例外處理器所能處理的例外型別與方法拋出的例外型別相符時,即為合適的例外處理器,
- 運行時系統從發生例外的方法開始,依次回查呼叫堆疊中的方法,直至找到含有合適例外處理器的方法并執行,當運行時系統遍歷呼叫堆疊而未找到合適的例外處理器,則運行時系統終止,同時,意味著Java程式的終止,
上面我們講述了什么是運行時例外以及一些處理方式,下面就再來看看什么是已檢查例外吧!
所有不是RuntimeException的例外,統稱為Checked Exception,又被稱為“已檢查例外”,如IOException、SQLException等以及用戶自定義的Exception例外, 這類例外在編譯時就必須做出處理, 否則無法通過編譯,
通常例外的處理方式有兩種:
-
使用“try/catch”捕獲例外
-
使用“throws”宣告例外,
下面就來詳細的聊聊吧!
例外的處理
上面已經提了,例外處理通常有2種方式,先看看捕獲例外吧,
捕獲例外是通過3個關鍵詞來實作的:try-catch-finally,用try來執行一段程式,如果出現例外,系統拋出一個例外,可以通過它的型別來捕捉(catch)并處理它,最后一步是通過finally陳述句為例外處理提供一個統一的出口,finally所指定的代碼都要被執行,
這個捕獲例外其實也是我們在面試的時候會經常碰到的問題,下面我們分別再來對各個部分做一個簡單的提示吧!
- try
一個try陳述句必須帶有至少一個catch陳述句塊或一個finally陳述句塊 ,當例外處理的代碼執行結束以后,不會再回到try陳述句去執行尚未執行的代碼,
- catch
每個try陳述句塊可以伴隨一個或多個catch陳述句,用于處理可能產生的不同型別的例外物件,在此介紹一些常用的方法,這些方法均繼承自Throwable類 ,
- toString ()方法,顯示例外的類名和產生例外的原因,
- getMessage()方法,只顯示產生例外的原因,但不顯示類名,
- printStackTrace()方法,用來跟蹤例外事件發生時堆疊的內容,
這里有一個需要特別注意的地方,那就是catch捕獲例外時的捕獲順序:
如果例外類之間有繼承關系,在順序安排上就需注意,越是頂層的類,越放在下面,再不然就直接把多余的catch省略掉, 也就是說先捕獲子類例外再捕獲父類例外,
- finally
finally陳述句塊中始終都要執行,除了遇到了System.exit(0)結束程式運行,針對這個特性,所以我們通常在finally中關閉程式塊已打開的資源,比如:關閉檔案流、釋放資料庫連接等,
即使try和catch塊中存在return陳述句,finally陳述句也會執行,是在執行完finally陳述句后再通過return退出,
在這里就有一道非常經典的一個面試題,
public class Test {
public static void main(String[]args) {
System.out.println(new Test().test());;
}
static int test(){
int x = 1;
try{
retun x;
}finally{
System.out.print("jdbk"+ ++x);
}
}
}
// 問輸出結果?
先解釋哈這里存在的玄妙吧!
看了上面的講述,我們都知道了當try和catch中有return時,finally仍然會執行,所以正常邏輯來說此題的答案應該是“jdbk2 2”,但這里存在一個陷阱,那就是:
finally是在return后面的運算式運算后執行的(此時并沒有回傳運算后的值,而是先把要回傳的值保 存起來,不管finally中的代碼怎么樣,回傳的值都不會改變,任然是之前保存的值),所以函式回傳值是 在finally執行前確定的,因此正確答案應該是:“jdbk2 1”,
還有一點需要注意的就是:finally中最好不要包含return,否則程式會提前退出,回傳值不是try或catch中保存的回傳值,
接下來再來講講宣告例外吧,它相對來說就比較簡單了,
在一些情況下,當前方法并不需要處理發生的例外,而是向上傳遞給呼叫它的方法處理,如果一個方法拋出多個已檢查例外,就必須在方法的首部列出所有的例外,之間以逗號隔開,
public static void readFile(String fileName) throws FileNotFoundException,IOException {
}
需要注意的地方就是:
- 在方法重寫中宣告例外時:子類重寫父類方法時,如果父類方法有宣告例外,那么子類宣告的例外范圍不能超過父類宣告的范圍,
- 宣告例外我們一般在server層中,在controller層或則資料訪問層一般是捕獲例外,
自定義例外
我們為什么要自定義例外?還不是因為在程式中,可能會遇到JDK提供的任何標準例外類都無法充分描述清楚我們想要表達的問題,此時我們就可以創建自己的例外類,即自定義例外類,
那我們怎么自定義例外類呢?相信你看了上面的例外類的家族圖應該就猜到了,不錯,自定義例外類只需從Exception類或者它的子類派生一個子類即可,如果你繼承Exception類,則為受檢查例外,必須對其進行處理;如果不想處理,可以讓自定義例外類繼承運行時例外RuntimeException類,通常我們自定義例外類應該包含2個構造器:一個是默認的構造器,另一個是帶有詳細資訊的構造器,這里舉一個例子,
/**IllegalAgeException:非法年齡例外,繼承Exception類*/
class IllegalAgeException extends Exception {
//默認構造器
public IllegalAgeException() {
}
//帶有詳細資訊的構造器,資訊存盤在message中
public IllegalAgeException(String message) {
super(message);
}
}
public void setAge(int age) throws IllegalAgeException {
if (age < 0) {
throw new IllegalAgeException("人的年齡不應該為負數");
}
this.age = age;
}
最后給大家講述一點使用例外機制的建議:
1.要避免使用例外處理代替錯誤處理,這樣會降低程式的清晰性,并且效率低下,
2.處理例外不可以代替簡單測驗---只在例外情況下使用例外機制,
3.不要進行小粒度的例外處理---應該將整個任務包裝在一個try陳述句塊中,
4.例外往往在高層處理,
公眾號:良許Linux
有識訓?希望老鐵們來個三連擊,給更多的人看到這篇文章
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/30494.html
標籤:Linux
上一篇:modprobe 加載模塊時 出現權限不允許提醒;Operation not permitted
下一篇:Shell:輸出幫助
