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等領域相關技術干貨,期待與您相遇!