Java 異常機制(也許是全網最獨特視角)
一、Java中的“異常“指什麼
-
什麼是異常
一句話簡單理解:異常是程式執行中的一些異常或者錯誤。
(純字面意思)
-
Error類 和 Exception類
Java中“萬物皆物件”,異常也不例外,
Java把異常當做物件來處理,並將異常分為兩大類——Error(錯誤)和Exception(異常),它們都是Throwable類的子類。
這裡看起來可能有點奇怪,什麼叫“把異常分為錯誤和異常兩類”??可以這樣粗暴地理解——異常有兩大類,一類是錯誤異常(Error),另一類是異常異常(Exception)。
至於為什麼這麼奇怪,我覺得既有翻譯的問題,也有Java文件沒說清楚的問題。(主要是翻譯的鍋)
Oracle的JavaSE官方文件是這樣說的:
An Error is a subclass of Throwable that indicates serious problems that a reasonable application should not try to catch. Most such errors are abnormal conditions.
The class Exception and its subclasses are a form of Throwable that indicates conditions that a reasonable application might want to catch.
所以個人見解,我們可以把Throwable這個類翻譯為“事故類 ”(單詞problem:問題、狀況、事故),這個“事故類”的物件具有可被丟擲的性質,且”事故類“Throwable有兩個子類“錯誤事故”(Error,對應致命的大事故)和"異常事故"(Exception,對應剩餘可以處理的事故)。
所以Java的“異常機制”這個翻譯很容易誤導人,讓人奇怪什麼叫異常包括錯誤和異常,EXception的異常和“異常機制”的異常,這兩個翻譯衝突了,所以我認為更應該翻譯為Java的“事故機制”。
Error類的常見子類有IOError、AWTError、VirtualMachineError等,
Exception類的常見子類有IOException、RuntimeException等。
-
Error和Exception的區別
Error通常是災難性的致命錯誤,是程式無法控制和處理的,當出現這類異常時,JVM一般會選擇終止執行緒;而Exception通常情況下是可以被程式處理的,並且在程式中應該儘可能的去處理這類異常。
個人總結:曾經糾結Error和Exception的區別糾結了好久,後來發現根本不用糾結,就當成一樣的東西就好了,都是“意外狀況”,只不過一個嚴重點一個不嚴重點而已。由於Error是嚴重的異常,對於程式已經致命了,所以並不需要捕獲(catch)或者宣告(throws),而Exception屬於不那麼嚴重,還可以“挽救”或者說“預判”的異常,所以可以被捕獲(catch)或者宣告(throws)來做出進一步處理。
二、異常的捕獲和丟擲
-
異常處理的五個關鍵字——try、catch、finally、throw、throws。
-
try 和 catch 關鍵字可以捕獲異常。
try/catch 程式碼塊放在異常可能發生的地方,try 程式碼塊中的程式碼會先被執行,catch 語句包含要捕獲異常型別的宣告。當 try 語句中的程式碼發生一個異常時,try 後面的 catch 塊就會被檢查,如果發生的異常是catch語句所宣告的異常型別的例項,則該異常會被傳遞到該 catch 塊並執行catch程式碼塊中的程式碼,類似於傳遞一個引數到方法中。
finally程式碼塊出現在catch程式碼塊之後,無論try程式碼塊中是否發生異常,finally程式碼塊中的程式碼總會被執行。
注意:1、try程式碼塊後必須有catch程式碼塊或者finally程式碼塊;
2、靠上的catch所宣告的異常型別不能是靠下的catc所宣告的異常型別的父類(如以下程式碼中,e1不是e2的父類)。
try{ //正常執行的程式碼 }catch(Exception1 e1){ //捕獲到Exception1類的異常後執行的程式碼 //捕獲到的異常被賦值給e1 }catch(Exception2 e2){ //捕獲到Exception2類的異常後執行的程式碼 //捕獲到的異常被賦值給e2 }finally{ //善後程式碼 }
-
throw 和 throws 關鍵字用於主動丟擲異常。
兩個關鍵字的區別是,throw用於丟擲一個異常,而throws用於宣告方法可能丟擲的異常。
throw只能丟擲一個異常物件,throws可以宣告多個可能發生的異常類。
即一個負責丟擲,一個負責宣告。
注意:1、若方法中有 異常(嚴格來說是檢查異常,詳見後文)丟擲,必須使用throws語句在方法頭處宣告異常,或者在方法體內使用try/catch語句將異常丟擲語句包圍(將throw語句置於try程式碼塊中);
2、若一個方法使用了throws語句宣告異常,則引用此方法的另一個方法必須使用throws語句在方法頭處宣告異常,或者使用try/catch語句將引用此方法的語句包圍(將引用此方法的語句置於try程式碼塊中)
public void test1(){ //使用try/catch語句處理異常 try{ throw new Exception(); }catch(Exception e){ System.out.println("Thers's an exception.") } } public void test2() throws Exception{ //使用throws語句在方法頭處宣告異常 throw new Exception(); } public void test3() throws Exception{ //引用test2也要宣告異常 test2(); } public void test4() throws Exception{ //引用test2也要宣告異常
總結:可以這樣理解,throw就是丟擲異常,try/catch就是處理異常,throws就是暫時不處理、交給引用自己的方法處理。
-
-
檢查異常(checked exception)和非檢查異常(unchecked exception)
檢查異常:除了Error類及其子類 和 RuntimeException類及其子類,其它的Throwable子類都是檢查異常。
非檢查異常:Error類及其子類 和 RuntimeException類及其子類。
檢查異常是編譯器要求程式必須處置的異常,這種異常的特點是Java編譯器會檢查它是否被捕獲(try/catch)或者宣告(throws),否則編譯不通過。非檢查異常是編譯器不要求強制處理的異常。
public viod test(){ //丟擲Error類物件但並不做處理,編譯也能通過。 throw new Error(); } public viod test(){ //丟擲RuntimeException類物件但並不做處理,編譯也能通過。 throw new RuntimeException(); } //Error類及其子類 和 RuntimeException類及其子類 都是非檢查異常,
-
執行時異常和非執行時異常
執行時異常:RuntimeException類及其子類。
非執行時異常:RuntimeException以外的Exception類及其子類。
其實執行時異常就是 除去Error類的非檢查異常,
如果我們不去處理執行時異常,JVM會接管處理,系統會把異常一直往上層拋,一直到最上層,
最上層丟擲之後,如果丟擲異常線上程中,這個執行緒就會退出,如果丟擲異常在主程式中,整個程式就退出了。
也就是說,如果不對執行時異常進行處理,程式會通過編譯並執行,出現執行時異常後,要麼是執行緒終止,要麼是主程式終止。
public class Draft { public static void test1(){ throw new RuntimeException(); } public static void test2(){ test1(); } public static void main(String[] args) { test2(); } }
執行以上程式碼,終端會出現以下結果,
Exception in thread "main" java.lang.RuntimeException
at Draft.test1(Draft.java:3)
at Draft.test2(Draft.java:6)
at Draft.main(Draft.java:9)
三、自定義異常
- 如果Java提供的內建異常型別不能滿足程式設計的需求,我們可以自定義異常類,只需要繼承Exception類或者它的子類,以上異常機制對自定義的異常類同樣適用。
呼,終於寫完咯!人生第一篇部落格,歡迎各路大佬指正!
此後會持續更新學習筆記,每一篇都會用心去寫去感悟。
原創宣告:本文完全為作者蘭勃基尼原創,轉載請宣告並附上原文連結https://www.cnblogs.com/ForJoy/p/16452920.html。作者各平臺使用者名稱如下
知乎:我求知若渴呀
部落格園:蘭勃基尼_CodeJoy
CSDN:蘭勃基尼_CodeJoy