前言
隨著項目的迭代,代碼中存在的分支判斷可能會越來越多,當裡面涉及到的邏輯比較複雜或者分支數量實在是多的難以維護的時候,我們就要考慮下,有辦法能讓這些代碼變得更優雅嗎?
正文
使用枚舉
這裡我們簡單的定義一個表示狀態的枚舉。
public enum Status {
NEW(0),RUNNABLE(1),RUNNING(2),BLOCKED(3),DEAD(4);
public int statusCode;
Status(int statusCode){
this.statusCode = statusCode;
}
}
那麼我們在使用的時候就可以直接通過枚舉調用了。
int statusCode = Status.valueOf("NEW").statusCode;
優雅的解決了下面代碼賦值的方式
if(param.equals("NEW")){
statusCode = 0;
}else if(param.equals("RUNNABLE")){
statusCode = 1;
}
...
善用 Optional
在項目中,總少不了一些非空的判斷,可能大部分人還是如下的用法
if(null == user){
//action1
}else{
//action2
}
這時候該掏出Optional這個秘密武器了,它可以讓非空校驗更加優雅,間接的減少if操作。沒了解過Optional的同學可自行Google,這裡就不再贅述。
Optional<user> userOptional = Optional.ofNullable(user);
userOptional.map(action1).orElse(action2);
/<user>
上面的代碼跟第一段是等效的,通過一些新特性讓代碼更加緊湊。
表驅動法
來自Google的解釋:表驅動法是一種編程模式,它的本質是,從表裡查詢信息來代替邏輯語句(if,case)。下面看一個案例,通過月份來獲取當月的天數(僅作為案例演示,獲取2月份的數據不嚴謹),普通做法:
int getMonthDays(int month){
switch(month){
case 1:return 31;break;
case 2:return 29;break;
case 3:return 31;break;
case 4:return 30;break;
case 5:return 31;break;
case 6:return 30;break;
case 7:return 31;break;
case 8:return 31;break;
case 9:return 30;break;
case 10:return 31;break;
case 11:return 30;break;
case 12:return 31;break;
default:return 0;
}
}
表驅動法實現方式
int monthDays[12] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int getMonthDays(int month){
return monthDays[--month];
}
其實這裡的表就是數組而已,通過直接查詢數組來獲得需要的數據,那麼同理,Map之類的容器也可以成為我們編程概念中的表。
Map, Function> action> actionsMap = new HashMap<>();
// 初試配置對應動作
actionsMap.put(value1, (someParams) -> { doAction1(someParams)});
actionsMap.put(value2, (someParams) -> { doAction2(someParams)});
actionsMap.put(value3, (someParams) -> { doAction3(someParams)});
// 省略 null 判斷
actionsMap.get(param).apply(someParams);
通過Java8的lambda表達式,我們把需要執行東西存進value中,調用的時候通過匹配key的方式進行。
提前判斷返回
在之前的文章《優化代碼裡的 “ 壞味道 ”》裡也有提過,如下語句
if(condition){
//dost
}else{
return ;
}
改為
if(!condition){
return ;
}
//dost
避免一些不必要的分支,讓代碼更精煉。
其他方法
除了上面提到的方法,我們還可以通過一些設計模式,例如策略模式,責任鏈模式等來優化存在大量if,case的情況,其原理會和表驅動的模式比較相似,大家可以自己動手實現一下,例如我們在Netty的使用過程中,可能會出現需要大量判斷不同的命令去執行對應動作的場景。
ServerHandler.java
if(command.equals("login")){
//執行登錄
}else if(command.equals("chat")){
//聊天
}else if(command.equals("broadcast")){
//廣播信息
}
....
該如何處理呢?這裡先賣個關子,大家可以先思考一下,筆記後續會寫一些關於Netty實現IM的文章,到時候會詳細介紹。
結語
最後要明確一點,不是所有的if/else,switch/case都需要優化,當我們發現有“痛點”或者“聞到代碼有壞味道”再來優化才是最好的,不然你可能會寫了一個從不擴展的可擴展代碼,所有的優化都是為了更好的迭代項目,更好的服務於業務,而不是為了優化而優化。
歡迎工作一到五年的Java工程師朋友們加入Java程序員開發: 721575865
群內提供免費的Java架構學習資料(裡面有高可用、高併發、高性能及分佈式、Jvm性能調優、Spring源碼,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多個知識點的架構資料)合理利用自己每一分每一秒的時間來學習提升自己,不要再用"沒有時間“來掩飾自己思想上的懶惰!趁年輕,使勁拼,給未來的自己一個交代!
閱讀更多 JAVA柯尼塞克丶 的文章