自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

一文帶你了解如何優(yōu)雅的處理錯(cuò)誤邏輯

開(kāi)發(fā) 項(xiàng)目管理
為了在異常中保護(hù)程序的流程的正確性,以至于不會(huì)出現(xiàn)“過(guò)分”的功能不可用,我們要為了異常編程。從而保證了程序的健壯性。

程序的健壯性

程序在運(yùn)行的時(shí)候總是不可避免地遇到各種錯(cuò)誤。這些錯(cuò)誤有一些是包含在原有的邏輯判斷中的。而有一些是被程序描述了,但是我們并不認(rèn)為它是正常邏輯的一部分。不論是什么形式的問(wèn)題,我們?cè)谶M(jìn)行我們預(yù)期的業(yè)務(wù)邏輯編程的同時(shí),不可避免地要為程序的異常進(jìn)行編程。

為了在異常中保護(hù)程序的流程的正確性,以至于不會(huì)出現(xiàn)“過(guò)分”的功能不可用,我們要為了異常編程。從而保證了程序的健壯性。

一般來(lái)說(shuō),如果我們能覆蓋系統(tǒng)所有的異常,那么我們的程序就將變得十分的堅(jiān)不可摧。顯然,這時(shí)候程序的健壯性就得到了體現(xiàn)。

不可放棄的可讀性

程序的健壯性是十分的必要的,因?yàn)檫@關(guān)系到系統(tǒng)的穩(wěn)定性。所以,系統(tǒng)的健壯性是我們不能拋棄的。但不得不說(shuō)的是,如果我們只關(guān)心系統(tǒng)的健壯性,那我們很容易就會(huì)讓代碼變得十分的糟糕,難以閱讀。

舉個(gè)例子,不論是不是出自自己的手里,我們有時(shí)候會(huì)看見(jiàn)這種代碼:

A a = getA();
if(a.status != xxx ){
B b = a.getB();
if(b.status != xxx ){
doSomething(b);
}
}

從程序的角度上判斷,當(dāng)程序的返回結(jié)果不滿足主要流程的需要的時(shí)候,我們就不執(zhí)行我們的邏輯。從程序的健壯性的角度上來(lái)說(shuō),上面的這部分代碼已經(jīng)滿足了業(yè)務(wù)的需要。但是他有什么問(wèn)題呢?如果我們將狀態(tài)的判斷去除,就可以簡(jiǎn)化為以下邏輯:

A a = getA();
B b = a.getB();
doSomething(b);

這個(gè)邏輯就非常清晰了,分為三個(gè)部分:獲取變量a,然后獲取a的屬性b,然后根據(jù)b進(jìn)行某種操作。盡管上下兩段代碼在正常流程上的處理是一樣的,而上面的代碼更是對(duì)異常流程進(jìn)行了處理。但是我們很容易就能發(fā)現(xiàn)其中的問(wèn)題:

不優(yōu)雅的處理異常邏輯,會(huì)導(dǎo)致程序變得難以閱讀。

盡管我們處理了異常,但是如果代價(jià)是讓我們的代碼邏輯混亂難以閱讀。那么我認(rèn)為這就不是一個(gè)的處理方式。

優(yōu)雅的處理錯(cuò)誤邏輯

我們希望在保證不損失程序可讀性的同時(shí)保證系統(tǒng)的健壯性。而一些編程的準(zhǔn)則能幫助我們達(dá)到目標(biāo)。

使用異常

我們有很多重的方法來(lái)描述程序是否滿足我們的預(yù)期。比如上文中的第一個(gè)例子,我們是通過(guò)A、B對(duì)象中的狀態(tài)字段來(lái)體現(xiàn)邏輯是否按照我們的預(yù)期來(lái)實(shí)現(xiàn)的。這個(gè)例子里面的字段并不是那么合理,但有時(shí)這種處理的方式是因?yàn)閷?duì)象本身的屬性包含這種描述狀態(tài)的字段,而我們就直接復(fù)用了這些字段用于在后續(xù)邏輯中對(duì)非期望數(shù)據(jù)進(jìn)行處理。但是這樣就存在問(wèn)題:

  1. 我們將處理異常的邏輯和處理正常邏輯的代碼混合編排。
  2. 由于狀態(tài)分散在不同的對(duì)象中,我們需要在對(duì)象被使用前為每個(gè)對(duì)象進(jìn)行判斷。

第一個(gè)問(wèn)題導(dǎo)致代碼的可讀性變得比較差。第二個(gè)問(wèn)題導(dǎo)致到進(jìn)行上有編碼的時(shí)候,會(huì)依賴下層的細(xì)節(jié)。如果編碼人不知道下層異常邏輯,則會(huì)錯(cuò)過(guò)對(duì)異常的處理。

而如果我們用異常來(lái)處理則代碼就可以變成:

try{
A a = getA();
B b = a.getB();
doSomething(b);
} catch (AStatusException e) {
e.printStackTrace();
} catch (BStatusException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}

可以看到這種處理失敗流程的方式可以可以讓“正常業(yè)務(wù)邏輯”保持完整,其中try中包裹的部分和上文中不做異常判斷的部分是一模一樣的,所以:

推薦使用異常(Exception)代替失敗狀態(tài),可以保證正常業(yè)務(wù)邏輯的完整性。

進(jìn)一步的,在《如何寫(xiě)好一個(gè)方法》一文中,我們提到:可以將異常單獨(dú)地封裝為一個(gè)方法,從而讓一個(gè)方法中只關(guān)注一件事,所以我們可以調(diào)整如下:

try{
tryDoSomething();
} catch (AStatusException e) {
e.printStackTrace();
} catch (BStatusException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}

...

private void tryDoSomething(){
A a = getA();
B b = a.getB();
doSomething(b);
}

這樣調(diào)整之后,我們就可以將處理異常的部分,單獨(dú)剝離出來(lái)。這樣,如果我們只關(guān)心正常業(yè)務(wù)邏輯,就只關(guān)心tryDoSomething()就可以了。

封裝異常

觀察上一小節(jié)中的代碼,我們可以發(fā)現(xiàn)對(duì)于tryDoSomething()的方法,我們進(jìn)行了兩種指定類型的catch操作,但是在當(dāng)前代碼中,這兩個(gè)類型的catch的處理動(dòng)作邏輯并沒(méi)有差別,也就是說(shuō)當(dāng)前的業(yè)務(wù)邏輯并不關(guān)心異常的類型。而進(jìn)一步地說(shuō),異常的類型實(shí)際上是底層方法的實(shí)現(xiàn)細(xì)節(jié)。所以,就會(huì)出現(xiàn)一個(gè)相互排斥的問(wèn)題:

底層實(shí)現(xiàn)(或者公共API)希望提供足夠信息的異常場(chǎng)景信息。

上層實(shí)現(xiàn)并不對(duì)所有的異常信息關(guān)心。

針對(duì)這兩種情況,我們可以通過(guò)使用異常進(jìn)行封裝的方法來(lái)對(duì)下層的異常進(jìn)行抽象,從而對(duì)上層調(diào)用屏蔽細(xì)節(jié),方法如下:

try{
tryDoSomethingWithSameException();
} catch (StatusException e) {
e.printStackTrace();
}
...

private void tryDoSomethingWithSameException(){
try{
tryDoSomething();
} catch (AStatusException e) {
throw new StatusException(e);
} catch (BStatusException e) {
throw new StatusException(e);
} catch (Exception e) {
throw new StatusException(e);
}
}

tryDoSomethingWithSameException()這個(gè)方法可能是在一個(gè)單獨(dú)的代理類中定義的,或者是通過(guò)其他方式定義的,但是總的來(lái)說(shuō),通過(guò)使用tryDoSomethingWithSameException()方法,我們?cè)谧钔鈱訉?shí)際調(diào)用的時(shí)候就只用關(guān)心StatusException的這個(gè)方法就可以了。

同時(shí),由于使用了

tryDoSomethingWithSameException() 方法,如果當(dāng)我們調(diào)整tryDoSomething();中的業(yè)務(wù)邏輯而產(chǎn)生新的異常的時(shí)候,我們就不需要調(diào)整主業(yè)務(wù)邏輯的文件了,而只用調(diào)整異常封裝類就可以了,就讓我們可以更少的修改業(yè)務(wù)主流程。

非受檢異常

你會(huì)發(fā)現(xiàn),在上文的方法中無(wú)論是tryDoSomething(),還是

tryDoSomethingWithSameException() 我們都沒(méi)有使用 throw。也就是說(shuō),我們使用的是“非受檢異?!?。那么如果如果我們使用“受檢異?!睍?huì)怎么樣呢,代碼會(huì)變成這樣:

private void tryDoSomething() throws AStatusException, BStatusException {
A a = getA();
B b = a.getB();
doSomething(b);
}

在方法上需要對(duì)方法內(nèi)拋出的異常進(jìn)行定義?;蛟S有的人認(rèn)為這種方式十分好,因?yàn)樽銐蛎鞔_,一眼就知道會(huì)出現(xiàn)什么異常。并且在上層進(jìn)行使用的時(shí)候我們也可以直觀地知道方法可能出現(xiàn)的異常。

但是這種方式的優(yōu)點(diǎn)也同樣成為了缺點(diǎn),因?yàn)楫惓5拿枋鲋苯幼兂闪朔椒ê灻械囊徊糠帧6矣捎谑鞘軝z異常,所以會(huì)逐級(jí)地向上傳遞,直到上層那里進(jìn)行了捕獲處理。也就是說(shuō),如果不想在當(dāng)前方法中處理異常的話,就要將異常添加到方法簽名上。從而使得調(diào)整一個(gè)底層邏輯新增一個(gè)異常的時(shí)候,會(huì)導(dǎo)致所有調(diào)用該方法的方法都需要進(jìn)行調(diào)整,而這顯然是不符合開(kāi)閉原則的。

當(dāng)然,對(duì)于一下關(guān)鍵的邏輯,你可能會(huì)需要讓開(kāi)發(fā)人員明確地知道可能會(huì)存在的異常。但是對(duì)于更多的一般情況,非受檢異常的使用,會(huì)更適合代碼的可維護(hù)性。

特殊對(duì)象代替異常

當(dāng)我們嘗試獲取一個(gè)列表的時(shí)候,可能會(huì)使用如下的方法:

List<File> files = getFileByPath("xxx");

我們會(huì)通過(guò)getFileByPath()嘗試獲取文件列表。那么針對(duì)“xxx”的這個(gè)變量,如果他不是一個(gè)有效的路徑,那就有可能存在異常邏輯。我們可以通過(guò)拋出一個(gè)"FileNotFoundException"的異常來(lái)描述這種的異常情況,但這就需要上層對(duì)異常邏輯進(jìn)行處理,這回導(dǎo)致增加額外的邏輯。

所以,當(dāng)上層對(duì)于下層的異常不敏感的時(shí)候,我們可以調(diào)整數(shù)據(jù)的返回值,讓他成為一種不會(huì)影響業(yè)務(wù)邏輯的特別返回值,從而減少整體的業(yè)務(wù)維護(hù)代碼。

以本節(jié)的例子舉例,就是當(dāng)異常的時(shí)候,在方法內(nèi)部進(jìn)行捕獲,然后使用"Collections.emptyList()"返回一個(gè)空的列表。這樣后續(xù)的處理邏輯就可以正常執(zhí)行。當(dāng)然要保證這樣的處理和你的業(yè)務(wù)是吻合的。

出入不歡迎null

不要用null!不要用null!不要用null!

不論出入都不用用null作為入?yún)⒒蛘叱鰠?。原因很?jiǎn)單,一旦你的代碼中中出現(xiàn)了返回null的代碼風(fēng)格,那么你所有的處理邏輯中都要對(duì)null做出判斷。即便java可以使用Optional簡(jiǎn)化連續(xù)為空的處理,但這是給自己增加沒(méi)有必要的工作量。假如本文中第一個(gè)例子的返回值可能為空,那么這個(gè)代碼就是有問(wèn)題的,因?yàn)閹讉€(gè)判斷里面都可能會(huì)拋出"NullPointerException"而本方法中沒(méi)有捕獲,上層要是也沒(méi)有的話,這次邏輯執(zhí)行就會(huì)直接以失敗告終。但是如果對(duì)null進(jìn)行判斷,代碼就會(huì)變成如下:

A a = getA();
if(a != null && a.status != xxx ){
B b = a.getB();
if(b != null && b.status != xxx ){
doSomething(b);
}

但起來(lái)沒(méi)有多少增加的邏輯,但是要知道當(dāng)所有的判斷中都需要處理這個(gè)情況的時(shí)候,就很可怕了。更可怕的是如果你忘記了其中的一個(gè)判斷,代碼就會(huì)在下一次的時(shí)候從不知道哪里拋出一個(gè)"NullPointerException"。

所以,為了減少不必要的業(yè)務(wù)邏輯維護(hù),不要讓null成為你“正常邏輯”中的一種返回。

最后

在進(jìn)行業(yè)務(wù)編碼的過(guò)程中,我們不可避免地需要處理正常邏輯之外的異常邏輯。但如果不處理好異常邏輯,那么異常邏輯的維護(hù)就會(huì)侵占正常邏輯的位置,讓系統(tǒng)整體的理解成本增高。所以,優(yōu)雅的處理異??梢宰屜到y(tǒng)的可維護(hù)性大大提高。

責(zé)任編輯:姜華 來(lái)源: 今日頭條
相關(guān)推薦

2023-11-20 08:18:49

Netty服務(wù)器

2023-11-06 08:16:19

APM系統(tǒng)運(yùn)維

2022-11-11 19:09:13

架構(gòu)

2023-03-31 08:16:53

Flutter優(yōu)化內(nèi)存管理

2022-02-24 07:34:10

SSL協(xié)議加密

2023-11-08 08:15:48

服務(wù)監(jiān)控Zipkin

2023-10-27 08:15:45

2020-02-02 15:14:24

HTTP黑科技前端

2024-02-04 09:44:41

量子計(jì)算量子量子物理

2020-10-08 14:32:57

大數(shù)據(jù)工具技術(shù)

2025-01-15 09:06:57

servlet服務(wù)器Java

2022-09-29 13:09:38

DataClassPython代碼

2022-04-28 09:22:46

Vue灰度發(fā)布代碼

2025-01-02 11:55:08

HashMapJava哈希沖突

2023-09-07 07:17:01

KubernetesCRI標(biāo)準(zhǔn)

2018-10-22 08:14:04

2022-02-18 10:13:07

SolrElasticSea開(kāi)源

2019-07-04 15:16:52

數(shù)據(jù)挖掘大數(shù)據(jù)算法

2022-09-06 11:21:49

光網(wǎng)絡(luò)光纖

2023-12-06 16:28:56

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)