作者:朱季謙鏈接:https://www.jianshu.com/p/93a9e0ce019c
(資料圖片)
說實話,其實我很討厭在代碼里大量使用if-else,一是因為該類代碼執(zhí)行方式屬于面向過程的,二嘛,則是會顯得代碼過于冗余。這篇筆記,主要記錄一些自己在工作實踐當(dāng)中針對if-else的優(yōu)化心得,將會不定期地長期更新。
看到網(wǎng)上蠻多人推薦使用策略模式來優(yōu)化if-else,但我總覺得,搞一堆策略類來優(yōu)化大批量if-else,雖然想法很好,但無意之中很可能又會創(chuàng)造出很多類對象,就顯得過于繁重了。若想使用策略模式來優(yōu)化大批量if-else,其實有一種更好的方式,這是策略模式+枚舉方式的改良。
1、根據(jù)if-else條件來判斷賦值的,如:
Stringid="";if(flag){id="a";}else{id="b";}
利用三目運(yùn)算符,可以直接優(yōu)化成一行代碼:
id=flag?"a":"b";
2、利用if-else條件來判斷調(diào)用方法,如:
Setset1=newHashSet<>();Setset2=newHashSet<>();if(flag){set1.add(id);}else{set2.add(id);}
利用三目運(yùn)算符,可以直接優(yōu)化成:
Setset1=newHashSet<>();Setset2=newHashSet<>();(flag?set1:set2).add(id);
Jdk1.8新特性Stream流有三個這樣API,anyMatch,allMatch,noneMatch,各自的作用如下:
anyMatch:判斷條件里任意一個滿足條件,則返回true;
allMatch:判斷條件里所有都滿足條件,則返回true;
noneMatch:判斷條件里所有都不滿足條件,則返回true;
它們的使用方式其實很簡單:
Listlist=Arrays.asList("a","b","c","d","");//任意一個字符串判斷不為空則為truebooleananyMatch=list.stream().anyMatch(s->StringUtils.isEmpty(s));//所有字符串判斷都不為空則為truebooleanallMatch=list.stream().allMatch(s->StringUtils.isEmpty(s));//沒有一個字符判斷為空則為truebooleannoneMatch=list.stream().noneMatch(s->StringUtils.isEmpty(s));
可見,根據(jù)以上三種實現(xiàn)方式,可以在某種程度上優(yōu)化if里判斷條件過多的情況,那么,在哪種場景里比較合適利用其優(yōu)化呢?
在日常實際開發(fā)當(dāng)中,我們可能會看到過這樣存在很多判斷條件的代碼:
if(StringUtils.isEmpty(str1)||StringUtils.isEmpty(str2)||StringUtils.isEmpty(str3)||StringUtils.isEmpty(str4)||StringUtils.isEmpty(str5)||StringUtils.isEmpty(str6)){.....}
這時,就可以考慮到,使用stream流來優(yōu)化,優(yōu)化后的代碼如下:
if(Stream.of(str1,str2,str3,str4,str5,str6).anyMatch(s->StringUtils.isEmpty(s))){.....}
這樣優(yōu)化后,是不是就比那堆if里堆積到一塊的條件更為優(yōu)雅了?
當(dāng)然,這只是針對或條件的,若是遇到與條件時,同樣可以用Stream來優(yōu)化,例如:
if(StringUtils.isEmpty(str1)&&StringUtils.isEmpty(str2)&&StringUtils.isEmpty(str3)&&StringUtils.isEmpty(str4)&&StringUtils.isEmpty(str5)&&StringUtils.isEmpty(str6)){.....}
使用Stream優(yōu)化后:
if(Stream.of(str1,str2,str3,str4,str5,str6).allMatch(s->StringUtils.isEmpty(s))){.....}
還有一個判斷任意都不為空的操作:
StringUtils.isNoneEmpty(str1,str2,str3)
優(yōu)化量比較多的面向過程的if-else語句,還可以考慮使用Map來優(yōu)化,雖然在一定程度上,創(chuàng)建一個額外map會占用內(nèi)存,但那丁點內(nèi)存對于現(xiàn)階段計算機(jī)而言,可以說不足掛齒。 下面使用一個案例來介紹下————
在一些祖?zhèn)骼洗a當(dāng)中,可能遇到過類似這樣又臭又冗余的if-else寫法:
publicStringgetDay(Stringday){if("Monday".equals(day)){return"今天上英語課";}elseif("Tuesday".equals(day)){return"今天上語文課";}elseif("Wednesday".equals(day)){return"今天上數(shù)學(xué)課";}elseif("Thursday".equals(day)){return"今天上音樂課";}elseif("Sunday".equals(day)){return"今天上編程課";}else{......}}
這時,可以根據(jù)具體場景,來考慮是否可以利用Map優(yōu)化,使用Map優(yōu)化的方式,是先在該類中定義一個static的map,類似這樣:
publicstaticfinalMapdayMap=ImmutableMap.builder().put("Monday","今天上英語課").put("Tuesday","今天上語文課").put("Wednesday","今天上數(shù)學(xué)課").put("Thursday","今天上音樂課").put("Sunday","今天上編程課").build();
定義完后,就直接在先前使用if-else的方法里,進(jìn)行這樣優(yōu)化:
publicStringgetDay(Stringday){returndayMap.get(day);}
這樣優(yōu)化后,業(yè)務(wù)方法里的判斷獲取值的處理,是不是就清爽了很多,當(dāng)然,這只是針對量比較多的if-else而言,若是比較少的判斷語句,再額外定義一個map來搞,隱約有畫蛇添足的嫌疑。
細(xì)心的讀者可能會發(fā)現(xiàn), 我在定義map的時候,使用到了一個ImmutableMap的東西,這是Google Guava里的一個類,可生成一個不可變的Map對象,這就意味著,初始化定義后,后續(xù)就無法再put修改了,它的這個特性可以保證線程的安全。一般用來替換if-else的map,我們就是要求在初始化定義后,就不會再允許修改了,因此,這個ImmutableMap生成的map,可以很好地幫我們實現(xiàn)這一點。另外,最重要一點是,使用這個ImmutableMap,可以實現(xiàn)鏈?zhǔn)骄幊?,就像上面定義的鏈?zhǔn)綄懛?,若是用傳統(tǒng)的map定義,就每次都要map.put()、map.put()地賦值。
前面提到過可使用策略枚舉來優(yōu)化大批量的if-else,當(dāng)然,若只是判斷獲不同條件來取值的代碼,可以考慮直接使用枚舉來優(yōu)化,其效果與map的處理效果類似。
還是用前面判斷課程的if-else為案例來優(yōu)化。
首先,先在類中定義一個枚舉:
publicenumdayEnum{Monday("今天上英語課"),Tuesday("今天上語文課"),Wednesday("今天上數(shù)學(xué)課"),Thursday("今天上音樂課"),Sunday("今天上編程課");publicStringvalue;dayEnum(Stringvalue){this.value=value;}}
定義完后,就可以類似前面map的方式,直接將判斷值去枚舉里獲取,然后直接返回獲取到的值,這樣寫法是不是也比較優(yōu)雅了。
publicStringgetDay(Stringday){returndayEnum.valueOf(day).value;}
在實際工作中,我曾經(jīng)遇到類似這樣的代碼,看起來像沒什么問題,但如果其中某個屬性值不幸為null,那么,恭喜你,你將會喜提一個NullPointerException異常。
Stringname=school.getGrades().getStuendt().getName();
若要處理這個可能出現(xiàn)的空指針異常,傳統(tǒng)寫法,可以寫一堆if-else語句來處理,就像這樣子——
Stringname=null;if(school!=null){Gradesgrade=school.getGrades();if(grade!=null){Studentstudent=grade.getStuendt();if(student!=null){name=student.getName();}}}
作為一個極度討厭if-else的人士,怎么能容忍這一堆層層嵌套的代碼存在呢!
在遇到這種層層嵌套的if-else判斷時,可以考慮使用jdk1.8新特性O(shè)ptional 類來優(yōu)化,優(yōu)化后的效果如下,頓時又優(yōu)雅了很多。
Stringname=Optional.ofNullable(school).flatMap(School::getGrades).flatMap(Grades::getStuendt).map(Student::getName).orElse(null);
關(guān)鍵詞: