java零基礎入門-高級特性篇(十) 異常 下

除了系統定義好的異常,在實際工作中,會需要按照業務邏輯定義各種自定義異常,特別是明確的知道某些情況下需要拋出指定異常的時候。因為系統定義的異常有時候不能滿足實際工作的需要。

自定義異常

現在有一個任務,編寫一個工具,包含兩個方法,一個是根據參數註冊用戶,一個是根據註冊的順序獲得用戶信息。這個工具是提供給其他人用的,也就是說,用工具的人不需要知道工具內部的邏輯,只需要按規矩辦事即可得到結果。這樣的好處是程序員B在使用工具的時候完全可以直接使用工具,不需要了解工具是如何編寫如何運行的,但是這也會帶來一個問題,如果工具出了錯,該怎麼辦?如果直接將錯誤信息拋給使用者,也就是讓程序員B看錯誤信息,由於使用者不了解工具的源代碼,可能排查錯誤會十分困難。所以在寫工具的時候,對異常進行「包裝」,返回給使用者一個一目了然的錯誤信息,才是最好的方法。

使用工具

這三個類大概是上圖中的關係,一個類是工具使用者CustomExceptionDemo。兩個是工具提供者,其中UserTool是工具方法,CustomException是自定義異常類。在提供工具的過程中,不可避免的需要對異常進行處理,比如在註冊用戶的時候要考慮如果用戶輸入的年齡超出正常的年齡怎麼辦?需要獲取的用戶不存在怎麼辦?發生異常怎麼辦?

自定義異常

先看自定義異常的類CustomException。定義一個自定義異常首先就是要繼承Exception,因為繼承了Exception這個自定義的異常才能被系統識別為異常,才能有異常的特性,比如被捕獲或者拋出。然後在自定義異常中實現兩個構造器,但是這兩個構造器都是直接調用父類的構造器。

工具方法

逐段看這個工具類。首先是registerUser這個方法,用來註冊用戶。這裡成功的話只是列印了一條註冊成功的信息,實際情況可能會在這裡做將用戶信息寫入數據等操作。如果用戶的年齡信息小於0或者大於150,這個情況是不應該存在的,所以需要手動拋出異常,但是java中又沒有一個叫做「用戶年齡錯誤」的異常,這裡就可以使用自定義異常。由於自定義異常有一個構造器是帶參數的,並且直接調用了Exception的構造器,所以這裡可以直接使用構造器創建一個異常信息。

再來看內部類User,這裡只是來複習一下前面的知識,單獨定義一個User類是完全可以的。這個內部類包含了年齡和姓名的屬性。

最後看getUserByNo這個方法。這個方法可以理解成根據用戶註冊的順序獲取用戶,這裡為了演示方便,在方法中直接定義了兩個User對象,然後將這兩個對象加入集合。當使用者使用工具的時候,傳入的是用戶的順序,獲取到該用戶的名稱。那麼問題出現了,這裡只有2個用戶,也就是可以通過下標0,1來獲取,但是一旦用戶傳入的是2,集合就會報錯。所以這裡判斷了順序參數和集合的數量,如果獲取的下標超過了集合中最後一個元素的下標,需要手動拋出一個自定義異常,並且指定信息「指定順序用戶不存在」。因為如果不拋出自定義異常,而是系統自己拋異常,會拋出下標越界的異常,對於調用者來說,這個異常的排查會非常困難。

使用者

看使用工具的地方,第一個方法沒有錯誤,輸出的是「註冊成功」。第二個方法會報錯,因為在工具類中,只模擬了2個用戶的集合,因此這裡獲取下標為3的用戶會拋出下標越界的異常。但是按照上面分析過的問題,如果直接拋出的是下標越界使用者排查問題難度很大,而使用自定義異常則可以明確的告訴使用者,是該用戶不存在。這就是使用自定義異常的好處。

自定義異常除了繼承Exception,還可以繼承Exception的子類,比如Runtimeexception。在工作中可以根據實際情況,具體選擇要使用的子類來創建自定義異常。

常見異常,下標越界和空指針

下面來看兩個最常見的異常是如何產生的,在後面的學習過程中,碰到這樣的異常了解其原因,解決起來會方便很多。

下標越界異常

這個異常最常出現在使用數組和集合的過程中,因為他們都可以通過下標來訪問元素。但是一旦指定的下標沒有元素,就會發生下標越界的異常。所以在使用數組和集合的時候,一定要注意在使用時,不要訪問沒有元素的下標。

下標越界

再來看看源代碼,不要怕,你能看懂。

源代碼

首先看這個異常類,IndexOutOfBoundsException繼承了Exception的子類RuntimeException,然後創建了兩個構造器。等等,是不是有點眼熟,為什麼感覺和上面例子中我們自定義的異常幾乎一樣?再來看看拋出異常的地方,在rangeCheck方法中,比較完下標和集合長度後拋出異常,跟我們上例中的用法也十分類似。其實,這些異常在java看來,就是java自己的「自定義異常」,我們其實是在使用java提供的工具,也就是說我們是調用者,java定義自己的異常,告訴我們(調用者)異常的錯誤信息。

空指針異常

NullPointerException空指針異常,通常是使用對象調用方法或者屬性的時候出現的,而這個對象如果是null就會出現空指針異常。

空指針

看了這個例子,各位是不是會覺得「你以為我傻呀,我怎麼會給對象賦值null」。其實這裡主要表達的是出現異常的原因,而對象為空的情況會有很多,比如注釋掉的代碼,如果此對象是另一個方法的返回值,是通過查詢資料庫得來的,那麼它完全有可能是null。這種情況也是最常見的,因為沒有顯式的賦值給對象null,但是如果數據查不到,最後賦值給對象的恰恰又是個null,如果沒有檢查對象是否為null就直接使用,就會發生空指針異常。

工作中如何處理異常

在實際的工作中,由於有各種各樣框架的加持,其實在處理異常的時候是跟常規處理方式有些許區別的。比如前面有說過spring這個大管家,這裡簡單介紹一下,一旦把異常交給管家來管理,我們該如何使用異常。

寫代碼講究的是思想,好的代碼講究的是低耦合,無侵入,這也是大家應該追求的境界。在spring中,就提供了很多類似的工具,比如spring中的全局異常處理,就做到了低耦合,無侵入。什麼是低耦合,無侵入?想像一下,你的代碼有30個類,100個方法,每個方法都捕獲了異常,當發生異常的時候列印日誌-「程序報錯了!」。你辛辛苦苦複製粘貼了100遍啊100遍,然後老闆有天心情不太好,給我改!改成「程序罷工啦~」。老闆一句話,你又得找到那100個方法,再來複制粘貼100遍啊100遍,是不是生無可戀?生不如死?

耦合度高,就是依賴度高,關係緊密,密不可分,同樣的邏輯可以提取成方法,可是異常沒法提取啊,只能複製粘貼了。

侵入式代碼,就是在業務邏輯中加入太多無關業務的代碼,比如異常處理,如果能保證在寫業務的時候完全不需要考慮異常那該多好!

你的夢想,spring為你實現了,spring簡直就是業界良心,擼碼神器啊。目前講解spring還太早,但是可以先體會一下這個框架為我們帶來的幸福生活。

全局異常

以上是spring的全局異常處理方式,管家功能強大,除了全局異常處理,還有別的方法處理異常,更加詳細的知識可以在各位學習spring框架後再作了解。

最後再吹一波,spring這麼強大,簡直就是 --- 帶你飛上天,與太陽肩並肩~


推薦閱讀:
相关文章