文/朱季謙
說實話,其實我很討厭在程式碼裡大量使用if-else,一是因為該類程式碼執行方式屬於程式導向的,二嘛,則是會顯得程式碼過於冗餘。這篇筆記,主要記錄一些自己在工作實踐當中針對if-else的優化心得,將會不定期地長期更新。
一、使用策略列舉來優化if-else
看到網上蠻多人推薦使用策略模式來優化if-else,但我總覺得,搞一堆策略類來優化大批量if-else,雖然想法很好,但無意之中很可能又會創造出很多類物件,就顯得過於繁重了。若想使用策略模式來優化大批量if-else,其實有一種更好的方式,這是策略模式+列舉方式的改良,我以前寫過這樣一篇優化文章,詳細直接點選該文了解:《策略列舉:消除在專案裡大批量使用if-else的優雅姿勢》
二、使用三目運算子來優化if-else
1、根據if-else條件來判斷賦值的,如:
String id="";
if(flag){
id="a";
}else{
id="b";
}
利用三目運算子,可以直接優化成一行程式碼:
id=flag?"a":"b";
2、利用if-else條件來判斷呼叫方法,如:
Set<String> set1=new HashSet<>();
Set<String> set2=new HashSet<>();
if(flag){
set1.add(id);
}else{
set2.add(id);
}
利用三目運算子,可以直接優化成:
Set<String> set1=new HashSet<>();
Set<String> set2=new HashSet<>();
(flag?set1:set2).add(id);
三、使用Stream優化if中判斷條件過多情況
Jdk1.8新特性Stream流有三個這樣API,anyMatch,allMatch,noneMatch,各自的作用如下:- anyMatch:判斷條件裡任意一個滿足條件,則返回true;
- allMatch:判斷條件裡所有都滿足條件,則返回true;
- noneMatch:判斷條件裡所有都不滿足條件,則返回true;
它們的使用方式其實很簡單:
List<String> list = Arrays.asList("a", "b", "c","d", "");
//任意一個字串判斷不為空則為true
boolean anyMatch = list.stream().anyMatch( s->StringUtils.isEmpty(s));
//所有字串判斷都不為空則為true
boolean allMatch = list.stream().allMatch( s->StringUtils.isEmpty(s));
//沒有一個字元判斷為空則為true
boolean noneMatch = list.stream().noneMatch( s->StringUtils.isEmpty(s));
可見,根據以上三種實現方式,可以在某種程度上優化if裡判斷條件過多的情況,那麼,在哪種場景裡比較合適利用其優化呢?
在日常實際開發當中,我們可能會看到過這樣存在很多判斷條件的程式碼:
if(StringUtils.isEmpty(str1) || StringUtils.isEmpty(str2) ||
StringUtils.isEmpty(str3) || StringUtils.isEmpty(str4) ||
StringUtils.isEmpty(str5) || StringUtils.isEmpty(str6)
){
.....
}
這時,就可以考慮到,使用stream流來優化,優化後的程式碼如下:
if(Stream.of(str1, str2, str3, str4,str5,str6).anyMatch(s->StringUtils.isEmpty(s))){
.....
}
這樣優化後,是不是就比那堆if裡堆積到一塊的條件更為優雅了?
當然,這只是針對或條件的,若是遇到與條件時,同樣可以用Stream來優化,例如:
if(StringUtils.isEmpty(str1) && StringUtils.isEmpty(str2) &&
StringUtils.isEmpty(str3) && StringUtils.isEmpty(str4) &&
StringUtils.isEmpty(str5) && StringUtils.isEmpty(str6)
){
.....
}
使用Stream優化後:
if(Stream.of(str1, str2, str3, str4,str5,str6).allMatch(s->StringUtils.isEmpty(s))){
.....
}
四、使用Map優化if-else
優化量比較多的程式導向的if-else語句,還可以考慮使用Map來優化,雖然在一定程度上,建立一個額外map會佔用記憶體,但那丁點記憶體對於現階段計算機而言,可以說不足掛齒。 下面使用一個案例來介紹下————在一些祖傳老程式碼當中,可能遇到過類似這樣又臭又冗餘的if-else寫法:
public String getDay(String day){
if("Monday".equals(day)){
return "今天上英語課";
}else if("Tuesday".equals(day)){
return "今天上語文課";
}else if("Wednesday".equals(day)){
return "今天上數學課";
}else if("Thursday".equals(day)){
return "今天上音樂課";
}else if("Sunday".equals(day)){
return "今天上程式設計課";
}else{
......
}
}
這時,可以根據具體場景,來考慮是否可以利用Map優化,使用Map優化的方式,是先在該類中定義一個static的map,類似這樣:
public static final Map<String,String> dayMap= ImmutableMap.<String, String>builder()
.put("Monday","今天上英語課")
.put("Tuesday","今天上語文課")
.put("Wednesday","今天上數學課")
.put("Thursday","今天上音樂課")
.put("Sunday","今天上程式設計課")
.build();
定義完後,就直接在先前使用if-else的方法裡,進行這樣優化:
public String getDay(String day){
return dayMap.get(day);
}
這樣優化後,業務方法裡的判斷獲取值的處理,是不是就清爽了很多,當然,這只是針對量比較多的if-else而言,若是比較少的判斷語句,再額外定義一個map來搞,隱約有畫蛇添足的嫌疑。
細心的讀者可能會發現, 我在定義map的時候,使用到了一個ImmutableMap的東西,這是Google Guava裡的一個類,可生成一個不可變的Map物件,這就意味著,初始化定義後,後續就無法再put修改了,它的這個特性可以保證執行緒的安全。一般用來替換if-else的map,我們就是要求在初始化定義後,就不會再允許修改了,因此,這個ImmutableMap生成的map,可以很好地幫我們實現這一點。另外,最重要一點是,使用這個ImmutableMap,可以實現鏈式程式設計,就像上面定義的鏈式寫法,若是用傳統的map定義,就每次都要map.put()、map.put()地賦值。
關於ImmutableMap的使用與原理,後續我會專門寫一篇文章來介紹。
五、使用列舉優化if-else
前面提到過可使用策略列舉來優化大批量的if-else,當然,若只是判斷獲不同條件來取值的程式碼,可以考慮直接使用列舉來優化,其效果與map的處理效果類似。還是用前面判斷課程的if-else為案例來優化。
首先,先在類中定義一個列舉:
public enum dayEnum {
Monday("今天上英語課"),
Tuesday("今天上語文課"),
Wednesday("今天上數學課"),
Thursday("今天上音樂課"),
Sunday("今天上程式設計課");
public String value;
dayEnum(String value){
this.value=value;
}
}
定義完後,就可以類似前面map的方式,直接將判斷值去列舉裡獲取,然後直接返回獲取到的值,這樣寫法是不是也比較優雅了。
public String getDay(String day){
return dayEnum.valueOf(day).value;
}
六、使用Optional類優化if-else
在實際工作中,我曾經遇到類似這樣的程式碼,看起來像沒什麼問題,但如果其中某個屬性值不幸為null,那麼,恭喜你,你將會喜提一個NullPointerException異常。
String name=school.getGrades().getStuendt().getName();
若要處理這個可能出現的空指標異常,傳統寫法,可以寫一堆if-else語句來處理,就像這樣子——
String name=null;
if(school!=null){
Grades grade=school.getGrades();
if(grade!=null){
Student student=grade.getStuendt();
if(student!=null){
name = student.getName();
}
}
}
作為一個極度討厭if-else的人士,怎麼能容忍這一堆層層巢狀的程式碼存在呢!
在遇到這種層層巢狀的if-else判斷時,可以考慮使用jdk1.8新特性Optional 類來優化,優化後的效果如下,頓時又優雅了很多。
String name = Optional.ofNullable(school)
.flatMap(School::getGrades)
.flatMap(Grades::getStuendt)
.map(Student::getName)
.orElse(null);
本文屬於if-else優化程式設計技巧總結,後續若在實踐中有新收穫,將持續更新......