Java異常捕獲的設計原則

每個軟件都可能遇到異常,所以從設計階段就要考慮異常處理的問題,納為業務流程的一部分。

異常是需要妥善處理的,但是處理的前提是發現異常,而發現異常的前提的對異常有清楚的認識,我們要先認識到程序中都有什么樣的異常(定義異常),然后在程序結構中檢測和拋出異常(捕獲異常),最后用恰當的業務流程去分別處理(處理異常)

所以,發現和處理異常的過程可以簡單歸納為定義->發現->處理的過程,也就是定義異常-->捕捉異常->處理異常。

一、定義異常

要定義異常,就要看看程序都可能有哪些異常,如何去為這些異常分類。

異常當前不只一種,只有一種異常是不能滿足業務流程需要的。

例如在線登錄失敗這種異常,只拋出一個“登錄失敗”是無法準確處理的,失敗是因為網絡連接失敗?還是用戶名密碼錯誤?這兩種錯誤類型,要分別去走不同的業務流程,一個要檢查網絡,一個要檢查用戶名密碼,只有定義成不同的異常,才能根據實際情況去引導用戶分別操作。

1.Throwable

在Java中,異常的基類是Throwable,它只引用了Serializable這個可序列化接口,基于Throwable,還有Exception、RuntimeException和Error這三個類,這幾個類之間的關系如下:

異常處理類之間的關系

我們看到從大的分支上來看,分為Error和Exception兩大類,我們先看看這兩類有什么區別。

2.Error和Exception

我們看一組對比:

Error ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Exception

check ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?uncheck(運行時)

主要在編譯時提示 ? ? ? ? ? ? ? 運行時提示

不建議捕獲 ? ? ? ? ? ? ? ? ? ? ? ? ?建議捕獲

Error錯誤,主要在開發時起檢查作用(check),編譯器在編譯時,根據已知可能存在的異常,提示開發者,例如,把一個String值直接賦給int對象,編譯器就會提示Error了。

Exception異常,是編譯器檢查不出來的(uncheck),是在軟件運行時才會發現的異常,也就是運行時異常(RuntimeException),例如,做一個3/0的運算,這是個算術錯誤,但是編譯器在編譯階段看不出錯誤,只有在運行階段才能發現異常。

Error和Exception這兩種異常,其實都是可以用try catch捕獲的,寫catch(Error e)/catch(Exception e)就可以捕獲,但是一般不建議捕獲Error錯誤,這是為什么呢?

因為分工不同,先看Exception,這是運行階段可能出現的異常,一般在某些特殊邏輯分支或參數下,才可能出現,開發者也應該對這種邏輯進行處理,所以建議捕獲異常進行處理;

但是Error是不建議捕獲的,前面說了,Error不是運行階段可能出現的錯誤,他本身就代表程序邏輯有硬傷,或者運行環境不正確,在這種情況下,即便是捕獲了異常,程序也沒有辦法繼續執行,所以建議不捕獲。

我們找兩個例子,ClassNotFoundException和NoClassDefFoundError,這兩個看起來都是找不到類導致的異常,但是一個是Exceptioin異常,一個是Error錯誤,我們對比一下,就能理解Error和Exception的區別了。

ClassNotFoundException,是個Exception異常,一般在反射時遇到,是動態加載時報錯的,動態加載是開發者故意設計的業務邏輯,本身就有失敗的可能,所有建議捕獲異常。

NoClassDefFoundError,是個Error錯誤,這個錯誤發生時,在編譯時都沒有問題,但是運行時,JVM或者ClassLoader去加載某個類,發現這個類找不到了,就會報這個錯誤。這一般是運行環境的問題,例如缺少庫文件什么的,這個錯誤與業務邏輯無關,是必須解決掉的錯誤,否則軟件無法繼續運行,所以不建議捕獲異常。

3.異常子類

異常子類一般都是Exception的子類,Java提供了豐富的異常類,開發者也可以自定義異常類,異常類的作用就是描述什么出了錯,和為什么出錯,例如:IllegalArgumentException("filepath is null"),就拋出了一個參數錯誤的異常,而且說明了出錯的原因是"filepath is null"。

在實際開發中,我們需要根據自己的業務場景,去選用或自定義異常類型,根據實際情況去拋出異常。

二、捕獲異常

前面一直在說定義異常的問題,接下來我們要捕獲到這些異常。在出現異常時,我們需要立即知道哪里出了異常,為什么會出異常,具體來說,就是定位到異常代碼,并為異常分類,去定義這個異常的消息內容。

1.定位

Java可以比較容易地定位到異常代碼,異常堆棧提供了導致異常的方法調用鏈,能精確定位到類名,方法,代碼行。

2.分類

分類就需要一定的設計經驗了,一方面要提前做好異常定義,另一方面要在代碼中準確拋出異常

例如:在讀取文件時,把文件地址作為參數,如果輸入一個空的文件地址,Java默認只會報一個NullPointerException空指針異常,也沒有異常消息,這種寬泛的分類下,我們只知道這里出現了異常,卻不知道為什么會異常,后面的異常處理就沒辦法做。

這種情況下,我們為了能精準地處理空文件地址的問題,就需要自己去判斷文件名是否為空,如果為空,則拋出一個IllegalArgumentException,并自定義一個"filepath is null"的異常消息傳出來,這樣后面處理時,就可以在這種情況下提示用戶“請輸入文件地址”,而不是簡單粗暴地報一句“出錯啦”了事。

3.捕獲

異常捕獲是需要融入到代碼邏輯中的,首先要預見可能的異常,然后定義異常及其異常消息,最后才能在代碼段中捕獲到相應的異常。

4.拋出

有時候,我們需要主動拋出異常,比如我們不希望用戶調用某些函數,或在某些邏輯分支中提前判斷并拋出異常,我們可以主動在代碼里throw一些異常,比如throw methodErr("visiting this method is not allowed");

三、處理異常

我們捕獲異常,最終都是為了走恰當的業務流程,去處理異常。

Java有兩種處理異常的方式,一是自己捕獲,用try catch去捕捉異常,在catch代碼里處理;另一種是讓調用者捕獲,用throw拋出異常,通知調用者去處理。

這兩種處理方式不是隨便選擇的,要看具體的業務,異常應該馬上捕獲,但不一定要馬上處理

例如:服務器查詢數據庫時,業務層查詢數據,會調用數據訪問層,這時如果數據庫連接失敗就會出現異常,這個異常如果在數據層自己捕獲到,就僅限于數據層知道了,業務層根本不知道出了異常,會誤以為數據庫中沒有這種數據。這時正確的做法應該是拋出異常,用throw向業務層拋出異常,讓業務層自己去處理,決定是重試連接,還是告知用戶。

異常的提示,是與業務相關的,如果需要用戶走不同的邏輯分支,就需要設計相關的界面和提示;如果需要反饋給開發者,就需要記錄日志并上傳到服務器。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,797評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,179評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,628評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,642評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,444評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,948評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,040評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,185評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,717評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,602評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,794評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,316評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,045評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,418評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,671評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,414評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,750評論 2 370

推薦閱讀更多精彩內容