Java異常體系概述
Java的異常體系結構
Java異常體系的根類是 Throwable, 所以當寫在java程式碼中寫throw拋出異常時,後面跟的對象必然是Throwable或其子類的對象。
其中Exception異常是指一些可以恢復的異常, 例如常見的NullPointerException空指針異常。
Error指的是一些致命的錯誤,無法通過程式程式碼手段恢復的異常,例如OutOfMemoryError記憶體溢出錯誤。
unchecked異常
在上圖中除了RuntimeException、Error及其子類都是屬於unchecked的異常類型外,其他的都是受編譯器checked檢查的異常。
unchecked不受編譯器檢查的異常, 是因為這些錯誤在程式運行過程中是可以通過編程手段去控制住的,
例如常見的NullPointerException空指針異常和IndexOutOfBoundsException數組下標越界的異常,這些都可以事先使用if (xx != null) 以及 if (xxx.size() > i)來控制,
或者就是完全無法通過程式手段控制,
例如OutOfMemoryError記憶體溢出異常和StackOverflowError棧溢出異常,這種Error因為無法通過程式碼層面if就能避免的,所以也屬於unchecked。
checked異常
checked在編譯過程中受到編譯器的檢查,如果程式沒有對該異常做catch處理或者向上一層拋出的話,程式將無法編譯通過,
常見的checked異常有FileNotFoundException文件不存在異常等,因為這種異常在編寫階段就可以預見,例如這個文件極有可能是不存在的,所以這種異常必須要拋出並要求程式作出處理。
總結
Throwable任何異常/錯誤的祖先類,屬於checked異常。
Exception異常,可以從異常中恢復執行的異常,屬於checked異常。
RuntimeException異常,預料之外的異常例如空指針、數組越界,屬於unchecked異常。
…Exception除了RuntimeException及其子類是unchecked異常,其他的Exception類都是checked異常。
Error錯誤,致命問題,無法從錯誤中恢復, 也屬於unchecked異常。
在開發過程中,如果一些可以預料的到的錯誤拋出異常時,盡量拋出checked異常,例如那個文件、某個數據一定可能會不存在的情況下,就要提示該方法的調用者,需要對這種情況進行處理,
如果是一些預料之外的異常,則可以使用RuntimeException,例如某個值規定一定是必須不為空,但是程式判斷時為空了,則要進行RuntimeException的拋出。
面試題
什麼是checked/unchecked/runtime exception?
- checked exception指的是除了Error、Runtime Exception及其子類之外的所有異常,
- unchecked exception指的是Error、Runtime Exception及其子類的異常,
- runtime exception屬於unchecked異常。
try/catch/finally的執行順序
- try用於包含運行時的程式碼塊,第一步執行,
- catch用於捕獲程式碼運行時可能發生的異常,第二步執行
當程式碼塊執行到某一步發生錯誤時,後面的程式碼將不會進行執行,
而是跳轉到catch的程式碼塊中,catch順序由上而下,以第一個可以捕獲到當前異常的catch進行執行其中的內容, - finally是程式不管有沒有發生異常,這裡的程式碼最終一定會執行,所以是第三步執行。
在finally中return數據會怎麼樣
由於finally在不管什麼情況下都會執行,所以finally中的return或覆蓋掉其他地方的return,最終以finally返回的為主,圖中最終返回結果是2。
throw和throws的區別
- throw是用於在程式運行過程中,如果碰到了覺得不正確的值或者結果,可以通過throw new XXX()來拋出一個異常,終止當前程式的繼續執行。
- throws是用於在方法簽名上指出該方法將拋出什麼異常,告訴調用者,調用此方法可能會產生的異常,讓調用者做相應的處理。
final、finally、finalize的區別
- final用於修飾類、方法、變數,在類上該類不可被繼承,在方法上,該方法不可被重寫,在變數上,該變數引用不可被更改。
- finally用於在try語句中,意味著finally包含的程式碼必須執行,不管有沒有異常。
- finalize是所有對象的一個方法,在該對象被回收前,將會被垃圾回收器調用,但是只會調用一次,一般可以在該方法中挽救當前將被回收的對象,例如使用一個變數引用當前對象,但是這種方式不可取,因為垃圾回收器不會保證該方法被執行完畢,可能正在賦值的過程中該對象就被回收了,
這個方法類似C++的析構函數,但是不穩定,官方也不推薦使用,只是因為歷史原因,為了讓C++程式設計師更適應Java作出的一個妥協。
結語
歡迎關注微信公眾號『碼仔zonE』,專註於分享Java、雲計算相關內容,包括SpringBoot、SpringCloud、微服務、Docker、Kubernetes、Python等領域相關技術乾貨,期待與您相遇!