java零基礎(chǔ)入門-高級(jí)特性篇(十) 異常 下
除了系統(tǒng)定義好的異常徘六,在實(shí)際工作中戈锻,會(huì)需要按照業(yè)務(wù)邏輯定義各種自定義異常锡移,特別是明確的知道某些情況下需要拋出指定異常的時(shí)候阁吝。因?yàn)橄到y(tǒng)定義的異常有時(shí)候不能滿足實(shí)際工作的需要。
自定義異常
現(xiàn)在有一個(gè)任務(wù)绷柒,編寫一個(gè)工具志于,包含兩個(gè)方法,一個(gè)是根據(jù)參數(shù)注冊(cè)用戶废睦,一個(gè)是根據(jù)注冊(cè)的順序獲得用戶信息伺绽。這個(gè)工具是提供給其他人用的,也就是說(shuō),用工具的人不需要知道工具內(nèi)部的邏輯憔恳,只需要按規(guī)矩辦事即可得到結(jié)果瓤荔。這樣的好處是程序員B在使用工具的時(shí)候完全可以直接使用工具,不需要了解工具是如何編寫如何運(yùn)行的钥组,但是這也會(huì)帶來(lái)一個(gè)問(wèn)題输硝,如果工具出了錯(cuò),該怎么辦程梦?如果直接將錯(cuò)誤信息拋給使用者点把,也就是讓程序員B看錯(cuò)誤信息,由于使用者不了解工具的源代碼屿附,可能排查錯(cuò)誤會(huì)十分困難郎逃。所以在寫工具的時(shí)候,對(duì)異常進(jìn)行“包裝”挺份,返回給使用者一個(gè)一目了然的錯(cuò)誤信息褒翰,才是最好的方法。
這三個(gè)類大概是上圖中的關(guān)系匀泊,一個(gè)類是工具使用者CustomExceptionDemo优训。兩個(gè)是工具提供者,其中UserTool是工具方法各聘,CustomException是自定義異常類揣非。在提供工具的過(guò)程中,不可避免的需要對(duì)異常進(jìn)行處理躲因,比如在注冊(cè)用戶的時(shí)候要考慮如果用戶輸入的年齡超出正常的年齡怎么辦早敬?需要獲取的用戶不存在怎么辦?發(fā)生異常怎么辦大脉?
先看自定義異常的類CustomException搞监。定義一個(gè)自定義異常首先就是要繼承Exception,因?yàn)槔^承了Exception這個(gè)自定義的異常才能被系統(tǒng)識(shí)別為異常镰矿,才能有異常的特性腺逛,比如被捕獲或者拋出。然后在自定義異常中實(shí)現(xiàn)兩個(gè)構(gòu)造器衡怀,但是這兩個(gè)構(gòu)造器都是直接調(diào)用父類的構(gòu)造器。
逐段看這個(gè)工具類安疗。首先是registerUser這個(gè)方法抛杨,用來(lái)注冊(cè)用戶。這里成功的話只是打印了一條注冊(cè)成功的信息荐类,實(shí)際情況可能會(huì)在這里做將用戶信息寫入數(shù)據(jù)等操作怖现。如果用戶的年齡信息小于0或者大于150,這個(gè)情況是不應(yīng)該存在的,所以需要手動(dòng)拋出異常百匆,但是java中又沒(méi)有一個(gè)叫做“用戶年齡錯(cuò)誤”的異常监嗜,這里就可以使用自定義異常卒暂。由于自定義異常有一個(gè)構(gòu)造器是帶參數(shù)的,并且直接調(diào)用了Exception的構(gòu)造器铁追,所以這里可以直接使用構(gòu)造器創(chuàng)建一個(gè)異常信息。
再來(lái)看內(nèi)部類User茫船,這里只是來(lái)復(fù)習(xí)一下前面的知識(shí)琅束,單獨(dú)定義一個(gè)User類是完全可以的。這個(gè)內(nèi)部類包含了年齡和姓名的屬性算谈。
最后看getUserByNo這個(gè)方法涩禀。這個(gè)方法可以理解成根據(jù)用戶注冊(cè)的順序獲取用戶,這里為了演示方便然眼,在方法中直接定義了兩個(gè)User對(duì)象艾船,然后將這兩個(gè)對(duì)象加入集合。當(dāng)使用者使用工具的時(shí)候高每,傳入的是用戶的順序屿岂,獲取到該用戶的名稱。那么問(wèn)題出現(xiàn)了觉义,這里只有2個(gè)用戶雁社,也就是可以通過(guò)下標(biāo)0,1來(lái)獲取,但是一旦用戶傳入的是2晒骇,集合就會(huì)報(bào)錯(cuò)霉撵。所以這里判斷了順序參數(shù)和集合的數(shù)量,如果獲取的下標(biāo)超過(guò)了集合中最后一個(gè)元素的下標(biāo)洪囤,需要手動(dòng)拋出一個(gè)自定義異常徒坡,并且指定信息“指定順序用戶不存在”。因?yàn)槿绻粧伋鲎远x異常瘤缩,而是系統(tǒng)自己拋異常喇完,會(huì)拋出下標(biāo)越界的異常,對(duì)于調(diào)用者來(lái)說(shuō)剥啤,這個(gè)異常的排查會(huì)非常困難锦溪。
看使用工具的地方,第一個(gè)方法沒(méi)有錯(cuò)誤府怯,輸出的是“注冊(cè)成功”刻诊。第二個(gè)方法會(huì)報(bào)錯(cuò),因?yàn)樵诠ぞ哳愔形荒M了2個(gè)用戶的集合则涯,因此這里獲取下標(biāo)為3的用戶會(huì)拋出下標(biāo)越界的異常复局。但是按照上面分析過(guò)的問(wèn)題,如果直接拋出的是下標(biāo)越界使用者排查問(wèn)題難度很大粟判,而使用自定義異常則可以明確的告訴使用者亿昏,是該用戶不存在。這就是使用自定義異常的好處档礁。
自定義異常除了繼承Exception角钩,還可以繼承Exception的子類,比如Runtimeexception事秀。在工作中可以根據(jù)實(shí)際情況彤断,具體選擇要使用的子類來(lái)創(chuàng)建自定義異常。
常見異常易迹,下標(biāo)越界和空指針
下面來(lái)看兩個(gè)最常見的異常是如何產(chǎn)生的宰衙,在后面的學(xué)習(xí)過(guò)程中,碰到這樣的異常了解其原因睹欲,解決起來(lái)會(huì)方便很多供炼。
下標(biāo)越界異常
這個(gè)異常最常出現(xiàn)在使用數(shù)組和集合的過(guò)程中,因?yàn)樗麄兌伎梢酝ㄟ^(guò)下標(biāo)來(lái)訪問(wèn)元素窘疮。但是一旦指定的下標(biāo)沒(méi)有元素袋哼,就會(huì)發(fā)生下標(biāo)越界的異常。所以在使用數(shù)組和集合的時(shí)候闸衫,一定要注意在使用時(shí)涛贯,不要訪問(wèn)沒(méi)有元素的下標(biāo)。
再來(lái)看看源代碼蔚出,不要怕弟翘,你能看懂。
首先看這個(gè)異常類骄酗,IndexOutOfBoundsException繼承了Exception的子類RuntimeException稀余,然后創(chuàng)建了兩個(gè)構(gòu)造器。等等趋翻,是不是有點(diǎn)眼熟睛琳,為什么感覺(jué)和上面例子中我們自定義的異常幾乎一樣?再來(lái)看看拋出異常的地方踏烙,在rangeCheck方法中师骗,比較完下標(biāo)和集合長(zhǎng)度后拋出異常,跟我們上例中的用法也十分類似讨惩。其實(shí)辟癌,這些異常在java看來(lái),就是java自己的“自定義異巢脚В”,我們其實(shí)是在使用java提供的工具,也就是說(shuō)我們是調(diào)用者靴患,java定義自己的異常仍侥,告訴我們(調(diào)用者)異常的錯(cuò)誤信息。
空指針異常
NullPointerException空指針異常鸳君,通常是使用對(duì)象調(diào)用方法或者屬性的時(shí)候出現(xiàn)的农渊,而這個(gè)對(duì)象如果是null就會(huì)出現(xiàn)空指針異常。
看了這個(gè)例子或颊,各位是不是會(huì)覺(jué)得“你以為我傻呀砸紊,我怎么會(huì)給對(duì)象賦值null”。其實(shí)這里主要表達(dá)的是出現(xiàn)異常的原因囱挑,而對(duì)象為空的情況會(huì)有很多醉顽,比如注釋掉的代碼,如果此對(duì)象是另一個(gè)方法的返回值平挑,是通過(guò)查詢數(shù)據(jù)庫(kù)得來(lái)的游添,那么它完全有可能是null。這種情況也是最常見的通熄,因?yàn)闆](méi)有顯式的賦值給對(duì)象null唆涝,但是如果數(shù)據(jù)查不到,最后賦值給對(duì)象的恰恰又是個(gè)null唇辨,如果沒(méi)有檢查對(duì)象是否為null就直接使用廊酣,就會(huì)發(fā)生空指針異常。
工作中如何處理異常? ??
在實(shí)際的工作中赏枚,由于有各種各樣框架的加持亡驰,其實(shí)在處理異常的時(shí)候是跟常規(guī)處理方式有些許區(qū)別的。比如前面有說(shuō)過(guò)spring這個(gè)大管家嗡贺,這里簡(jiǎn)單介紹一下隐解,一旦把異常交給管家來(lái)管理,我們?cè)撊绾问褂卯惓诫睬!?/p>
寫代碼講究的是思想煞茫,好的代碼講究的是低耦合,無(wú)侵入摄凡,這也是大家應(yīng)該追求的境界续徽。在spring中,就提供了很多類似的工具亲澡,比如spring中的全局異常處理钦扭,就做到了低耦合,無(wú)侵入床绪。什么是低耦合客情,無(wú)侵入其弊?想象一下,你的代碼有30個(gè)類膀斋,100個(gè)方法梭伐,每個(gè)方法都捕獲了異常,當(dāng)發(fā)生異常的時(shí)候打印日志-“程序報(bào)錯(cuò)了仰担!”糊识。你辛辛苦苦復(fù)制粘貼了100遍啊100遍,然后老板有天心情不太好摔蓝,給我改赂苗!改成“程序罷工啦~”。老板一句話贮尉,你又得找到那100個(gè)方法拌滋,再來(lái)復(fù)制粘貼100遍啊100遍,是不是生無(wú)可戀绘盟?生不如死鸠真?
耦合度高,就是依賴度高龄毡,關(guān)系緊密吠卷,密不可分,同樣的邏輯可以提取成方法沦零,可是異常沒(méi)法提取啊祭隔,只能復(fù)制粘貼了。
侵入式代碼路操,就是在業(yè)務(wù)邏輯中加入太多無(wú)關(guān)業(yè)務(wù)的代碼疾渴,比如異常處理,如果能保證在寫業(yè)務(wù)的時(shí)候完全不需要考慮異常那該多好屯仗!
你的夢(mèng)想搞坝,spring為你實(shí)現(xiàn)了,spring簡(jiǎn)直就是業(yè)界良心魁袜,擼碼神器啊桩撮。目前講解spring還太早,但是可以先體會(huì)一下這個(gè)框架為我們帶來(lái)的幸福生活峰弹。
以上是spring的全局異常處理方式店量,管家功能強(qiáng)大,除了全局異常處理鞠呈,還有別的方法處理異常融师,更加詳細(xì)的知識(shí)可以在各位學(xué)習(xí)spring框架后再作了解。
最后再吹一波蚁吝,spring這么強(qiáng)大旱爆,簡(jiǎn)直就是 ---? 帶你飛上天舀射,與太陽(yáng)肩并肩~