java如何優(yōu)雅的處理異常 Java是c 實現(xiàn)的,為啥Java的異常處理更完善?
Java是c 實現(xiàn)的,為啥Java的異常處理更完善?這話很沒理由,那第一個低級語言編譯器應(yīng)該機(jī)器語言實現(xiàn)的呢,為啥功能越來越大系統(tǒng)完善?現(xiàn)在的編譯器很多都是自舉,用老版本開發(fā)新版本,功能又是更加完善
Java是c 實現(xiàn)的,為啥Java的異常處理更完善?
這話很沒理由,那第一個低級語言編譯器應(yīng)該機(jī)器語言實現(xiàn)的呢,為啥功能越來越大系統(tǒng)完善?
現(xiàn)在的編譯器很多都是自舉,用老版本開發(fā)新版本,功能又是更加完善系統(tǒng)
當(dāng)然是越標(biāo)準(zhǔn)封裝越系統(tǒng)完善啊,這跟用什么實現(xiàn)方法完全沒有關(guān)系,不是他所有的機(jī)制一定會是底層直接可以提供的
Java的trycatch也可以能捕捉全部異常,c的trycatch沒有辦法去捕獲部分十分,Java是怎么能夠做到的?
究竟你說的”更完善系統(tǒng)”具體指的是什么?你問題不說很清楚怎么回答我?
如何優(yōu)雅的設(shè)計Java異常?
異樣的類別
正如我們所明白的,java中的異樣的超類是(后文省略為Throwable),它有兩個都很有用的子類,(后文省略為Exception)和(后文省略為Error),其中Error由JVM虛擬機(jī)進(jìn)行管理,如我們所熟知的OutOfMemoryError十分等,因為我們本文不了解Error無比,那你我們細(xì)說一下Exception異常。
Exception異樣有個比較好最重要的子類,叫做什么RuntimeException。我們將RuntimeException或其他繼承自RuntimeException的子類一般稱非受檢異樣(invalidException),其他繼承自Exception異樣的子類一般稱受檢十分(blockedException)。本文重點來關(guān)注看看受檢異常和非受檢異樣這兩種極其。
該如何選擇異常
從筆者的開發(fā)經(jīng)驗來看,如果不是在一個應(yīng)用中,必須旗下一個方法(如某個功能的service方法),這個方法假如中間肯定出現(xiàn)異樣,這樣的話你必須判斷這個無比又出現(xiàn)之后有無全局函數(shù)者可以不如何處理,而且你是否需要如果能全局函數(shù)者并且處理,如果不是動態(tài)鏈接庫者也可以如何處理,但是你也希望內(nèi)部函數(shù)者通過處理,那就就要拋出受檢異常,警告動態(tài)創(chuàng)建者在不使用你的方法時,判斷到要是擲下異常時如果接受處理。
幾乎完全一樣的,如果在寫某個方法時,你以為這是個無意中十分,理論上說,你覺著運(yùn)行時很可能會出現(xiàn)什么問題,而這些問題或許并非定然再一次發(fā)生的,也不要全局函數(shù)者總是顯示的通過異常來確認(rèn)業(yè)務(wù)流程你操作的,那你這時就可以使用一個RuntimeException這樣的非受檢異樣.
再說,估計也我上邊說的這段話,你讀了很多遍也始終總覺得艱澀了。
那么,請領(lǐng)著我的思路,在慢慢仔細(xì)體會幫一下忙。
什么時候才要拋異樣
首先我們是需要打聽一下一個問題,什么時候才不需要拋異常?異常的設(shè)計是方便給開發(fā)者在用的,但并非亂是用,筆者相對于什么時候拋無比這個問題也問了很多朋友,能給出確切答案的倒是不多。反正這個問題很簡單,如果不是你總覺得某些”問題”幫忙解決不了了,那就你就是可以拋出異常了。
比如,你在寫一個service,其中在寫到某段代碼處,你發(fā)現(xiàn)到很可能會有一種問題,那么就請甩出異常吧,不會相信我,你此時甩出十分將是一個最佳的方法時機(jī)。
應(yīng)該要丟出整樣的極其
打聽一下完了什么時候才要一拋異常后,我們再認(rèn)真思索一個問題,真的當(dāng)我們拋出異常時,我們應(yīng)該是選用比較整樣的極其呢?到底是是受檢十分還是非受檢異常呢(RuntimeException)呢?
我來通俗的解釋幫一下忙這個問題,先從受檢異樣你說起,假如有那樣的話一個業(yè)務(wù)邏輯,不需要從某文件中讀取數(shù)據(jù)某個數(shù)據(jù),這個加載能操作可能會是由于文件被刪除掉等其他問題導(dǎo)致沒能獲取使再次出現(xiàn)讀取數(shù)據(jù)錯誤,那么還得從redis或mysql數(shù)據(jù)庫中再去資源此數(shù)據(jù),參考萬分感謝代碼,getKey(Integer)為入口程序.
可以了,看了以上代碼以后,你或許心中有一些想法,原來受檢十分這個可以控制義務(wù)邏輯,對,是啊,按照受檢異常真的可以不操縱業(yè)務(wù)邏輯,可是千萬記住千萬不能這樣在用,我們應(yīng)該是合不合理的甩出異常,是因為程序本身才是流程,異樣的作用單單是當(dāng)你通過不出去的時候能找到的一個借口只不過是,它并不能不能以為壓制程序流程的入口或出口,如果不是這樣的使用的話,是在將異常的作用逐漸擴(kuò)大化,這樣的可以說會造成代碼復(fù)雜程度的增加,耦合性會增加,代碼可讀性減低等問題。
那么就肯定會別可以使用這樣的無比嗎?不過也不是,在是真的有這樣的需求的時候,我們可以這樣的在用,只是千萬記住,不要把它真有當(dāng)作完全控制流程的工具或手段。這樣也不知什么時候才要丟出這樣的極其呢?要考慮到,如果不是動態(tài)創(chuàng)建者調(diào)用程序出錯后,一定得讓動態(tài)鏈接庫者對此錯誤通過處理才是可以,柯西-黎曼方程這樣的要求時,我們才能夠考慮使用受檢異樣。
接下來,我們來看一下非受檢十分呢(RuntimeException),相對于RuntimeException這種極其,我們當(dāng)然很多見,比如說/等,這樣的話這種無比我們時候擲下呢?
當(dāng)我們在寫某個方法的時候,肯定會偶然路過遇到某個錯誤,我們其實這個問題時不運(yùn)行時肯定為發(fā)生的,而且理論上講,沒有這個問題的話,程序?qū)⑹嵌颊O雸?zhí)行的時候,它不噬靈鬼斬具體的要求動態(tài)鏈接庫者一定得能捕捉這個異常,此時拋出RuntimeException十分。
舉個例子,當(dāng)傳來一個路徑的時候,需要回一個路徑填寫的File對象:
上述事項例子是因為,如果全局函數(shù)者內(nèi)部函數(shù)getFiles(String)的時候如果不是path是空,那就就拋出空指針極其(它是RuntimeException的子類),全局函數(shù)者不用什么顯示的接受try…catch…操作進(jìn)行強(qiáng)制破軍處理.這就要求全局函數(shù)者在調(diào)用這樣的方法時先進(jìn)行驗證,盡量減少再一次發(fā)生RuntimeException.追加:
估計最好選擇哪種極其
實際以上的描述和舉例說明,可以總結(jié)歸納出一個結(jié)論,RuntimeException異常和受檢無比之間的區(qū)別應(yīng)該是:是否是強(qiáng)制具體的要求調(diào)用者需要去處理此異常,要是噬魂之手具體的要求調(diào)用者要進(jìn)行處理,這樣的話就可以使用受檢極其,不然就選擇類型非受檢無比(RuntimeException)。好象來講,假如沒有特殊的方法的要求,我們我建議你使用RuntimeException十分。
場景推薦和技術(shù)選型架構(gòu)描述
很顯然我們所知,比較傳統(tǒng)的項目全是以MVC框架為基礎(chǔ)接受開發(fā)的,本文主要從建議使用restful風(fēng)格接口的設(shè)計來可以體驗幫一下忙異常處理的優(yōu)雅。
我們把關(guān)注點放在restful的api層(和web中的controller層帶有)和service層,想研究一下在service中如何一拋十分,后再api層如何通過捕捉獵物因此轉(zhuǎn)化異常。
建議使用的技術(shù)是:spring-boot,jpa(hibernate),mysql,如果不是對這些技術(shù)又不是太熟得不能再熟,讀者必須一一泛讀相關(guān)材料。
業(yè)務(wù)場景描述
選擇一個也很最簡單業(yè)務(wù)場景,以電商中的收貨地址管理為例,用戶在移動端參與購買商品時,要并且收貨地址管理,在項目中,提供給一些給移動端進(jìn)行訪問的api接口,如:直接添加收貨地址,刪除收貨地址,更改后收貨地址,默認(rèn)收貨地址設(shè)置,收貨地址列表可以查詢,單個確認(rèn)發(fā)貨地址查詢等接口。
統(tǒng)合約束條件
可以啦,這個是設(shè)置好的一個很基本的業(yè)務(wù)場景,肯定,無論什么樣的api操作,其中都中有一些規(guī)則:
添加收貨地址:入?yún)?
用戶id
收貨地址實體信息
加以約束:
用戶id不能為空,且此用戶雖然是修真者的存在的
收貨地址的沒有必要字段沒法為空
假如用戶還沒有收貨地址,當(dāng)此收貨地址創(chuàng)建時設(shè)置里成默認(rèn)收貨地址—
刪除收貨地址:入?yún)?
用戶id
收貨地址id
強(qiáng)制力:
用戶id沒法為空,且此用戶倒是是未知的
收貨地址又不能為空,且此收貨地址倒是是存在地的
確認(rèn)此收貨地址是否是用戶的收貨地址
可以確定此收貨地址是否需要為默認(rèn)收貨地址,要是是設(shè)置成收貨地址,這樣的話又不能通過刪掉
你要改收貨地址:入?yún)?
用戶id
收貨地址id
約束:
用戶id不能不能為空,且此用戶的確是存在的
收貨地址沒法為空,且此收到貨地址倒是是存在的
推測此收貨地址如何確定是用戶的收貨地址
設(shè)置成地址設(shè)置:入?yún)?
用戶id
收貨地址id
管理和約束:
用戶id不能為空,且此用戶確實是是修真者的存在的
收貨地址不能為空,且此收貨地址雖然是修真者的存在的
可以確定此收貨地址是否是是用戶的收貨地址
收貨地址列表網(wǎng)上查詢:入?yún)?
用戶id
約束力:
用戶id不能不能為空,且此用戶倒是是未知的
單個收貨地址查詢:入?yún)?
用戶id
收貨地址id
強(qiáng)制力:
用戶id不能不能為空,且此用戶雖然是存在的
收貨地址不能為空,且此收貨地址確實是是未知的
判斷此收貨地址是否是用戶的收貨地址
強(qiáng)制力判斷和技術(shù)選型
對此根據(jù)上述規(guī)定列下的約束條件和功能列表,我選擇幾個都很典型的異常處理場景并且分析:直接添加收貨地址,徹底刪除收貨地址,資源收貨地址列表。
這樣的話應(yīng)該要有哪些必要的知識儲備呢,讓我們查查收貨地址這個功能:
再添加收貨地址中必須對用戶id和收貨地址實體信息就行校驗,那就相對于非空的判斷,我們怎么接受工具的選擇呢?比較傳統(tǒng)的判斷如下:
上邊的例子,如果只判斷uid為空好在,要是再去判斷address這個實體中的某些必要屬性是否需要為空,在字段很多的情況下,這說白是災(zāi)難性的。
那我們應(yīng)該要怎摸并且這些入?yún)⒌呐袛嗄?,給大家可以介紹兩個知識點:
Guava中的Preconditions類實現(xiàn)了很多入?yún)⒎椒ǖ呐袛?/p>
jsr303的validation規(guī)范(目前實現(xiàn)程序都很全的是hibernate實現(xiàn)程序的hibernate-validator)
如果沒有使用了這兩種推薦技術(shù),那么入?yún)⒌呐袛鄷兊卯惓:唵吸c比較多。推薦一下大家多在用這些成熟的技術(shù)和jar工具包,他可以不會減少很多不必要的工作量。我們只不需要把重心放到業(yè)務(wù)邏輯上。而應(yīng)該不會只不過這些入?yún)⒌呐袛嗟⒄`時間更多的時間。
怎么優(yōu)雅的啊,設(shè)計java極其domain詳細(xì)介紹
據(jù)項目場景來看,不需要兩個domain模型,一個是用戶實體,一個是地址實體.
Addressdomain追加:
Userdomain追加:
可以啦,上邊是一個模型關(guān)系,用戶-收貨地址的關(guān)系是1-n的關(guān)系。上邊的@Data是使用了一個就是lombok的工具,它自動導(dǎo)入了Setter和Getter等方法,用起來非常方便,感興趣的讀者是可以無法清楚再看看。
dao可以介紹
數(shù)據(jù)連接層,我們不使用了spring-data-jpa這個框架,它具體的要求我們只要不能繼承框架提供的接口,并且通過約定對方法接受取名,就是可以能完成我們想要的數(shù)據(jù)庫操作。
用戶數(shù)據(jù)庫操作不勝感激:
收貨地址操作如下:
如果說讀者所看見的,我們的DAO只必須能繼承JpaRepository,它就早幫我們結(jié)束了都差不多的CURD等操作,假如想知道一點一些跪求spring-data的這個項目,請可以參考再看看spring的官方文檔,它比不方案我們對異常的研究。
Service異樣設(shè)計
ok,再一次到了我們的重點了,我們要結(jié)束service一些的部分操作:直接添加收貨地址,刪出收貨地址,獲取收貨地址列表.
首先看我的service接口定義:
我們來參與看看利用:
添加收貨地址
簡單以后再來看下之前收拾好的約束條件:
入?yún)?
用戶id
收貨地址實體信息
管理和約束:
用戶id沒法為空,且此用戶倒是是存在的
收貨地址的必要的話字段沒法為空
如果沒有用戶還沒有收貨地址,當(dāng)此收貨地址創(chuàng)建家族時設(shè)置里成默認(rèn)收貨地址
先看以上代碼利用:
其中,也完成了根據(jù)上述規(guī)定所詳細(xì)解釋的三點約束條件,當(dāng)三點約束條件都不滿足時,才可以接受都正常的業(yè)務(wù)邏輯,不然將擲下異樣(象在此處建議您一拋運(yùn)行時十分-RuntimeException)。
能介紹以下以上我所都用到的技術(shù):
1、(T t)這個是建議使用Guava中的參與推測的,是因為service中應(yīng)用的不驗證較低,所以我我建議你將Preconfitions把它改成靜態(tài)導(dǎo)入的
當(dāng)然了Guava的github中的只能說明也個人建議我們那樣建議使用。
2、(validator,address)這個使用了hibernate實現(xiàn)的jsr303規(guī)范來做的,必須傳遍一個validator和一個是需要驗正的實體,那么validator是該如何查看的呢,萬分感謝:
他將資源一個Validator對象,然后再我們在service中參與吸納便是可以可以使用了:
那么BeanValidators這個類是要如何實現(xiàn)程序的?不過實現(xiàn)很很簡單,只要去可以確定jsr303的標(biāo)示注解就就ok啦了。
這樣jsr303的注解寫哪了呢?其實是寫在address實體類中了: