7 种让 if / else 变得更加优雅的方式,你 pick 了吗?
前言
判斷可以說是我們程序中必不可少的邏輯處理方式,最簡單的就是 if / else 語句,可很多人就因為判斷必不可少而讓我們的程序因為 if / else 變得臃腫和冗長,而隨著時間推移,業務的增加,導致代碼邏輯復雜,維護性差。
接下來我將介紹 7 種方式讓我們的代碼變得更加優雅。
1. 簡化 else
場景:符合/不符合條件的操作無交集。
優化前:
if?(id?==?null)?{//?TODO?新增記錄 }?else?{//?TODO?修改記錄 }優化后:
if?(id?==?null)?{//?TODO?新增記錄return; } //?TODO?修改記錄2. 三目運算符
場景:符合/不符合條件操作后的返回值不同。
優化前:
String?name; if?(user?==?null)?{name?=?"無名氏"; }?else?{name?=?user.getName(); }優化后:
String?name?=?user?==?null???"無名氏"?:?user.getName();3. Java 8 Optional 類
Optional 可以把它想象成一個容器,值存在則 isPresent() 為 true,再調用 get() 會返回該對象。
場景:需要對值進行 null 判斷。
優化前:
String?name; if?(user?==?null)?{name?=?"無名氏"; }?else?{name?=?user.getName(); }優化后:
// ofNullable()里可以放 null 值;of()里放 null 會拋出空指針異常 NullPointerException Optional<User>?optionalUser?=?Optional.ofNullable(user); String?name?=?optionalUser.isPresent()???optionalUser.get().getName()?:?"無名氏";Optional 的另一種使用方式
優化前:
private?void?printName(String?name)?{if?(name?==?null)?{name?=?"無名氏";}log.info("姓名:{}",?name); }優化后:
private?void?printName(String?name)?{//?如果值存在,正常返回里面的值,否則返回默認值(無名氏)Optional<String>?optional?=?Optional.ofNullable(name);log.info("姓名:{}",?optional.orElse("無名氏")); }優點:可以很好地避免煩人的 NPE。
4. 衛語句
“如果代碼中使用的 if / else 超過了三層,建議替換,避免后續代碼維護困難。
”場景:多種條件判斷,都為 true 才能執行。
優化前:
if?(id?==?null)?{log.error("id?為空");return; }?else?if?(name?==?null)?{log.error("姓名為空");return; }?else?if?(age?<?0)?{log.error("年齡需要大于0");return; }???????? //?TODO?正常執行優化后:
if?(id?==?null)?{log.error("id?為空");return; } if?(name?==?null)?{log.error("姓名為空");return; } if?(age?<?0)?{log.error("年齡需要大于0");return; } //?TODO?正常執行優點:可讀性高;當有條件不需要后可以直接刪除相應“開關”,更加直觀。
5. switch
“如果代碼中使用的 if else 超過了三層,建議替換,避免后續代碼維護困難。
”場景:不同條件下執行的操作或返回的值不一樣
優化前:
int?a?=?2; int?b?=?5; if?("PLUS".equals(opt))?{return?a?+?b; }?else?if?("MINUS".equals(opt)){return?a?-?b; }?else?if?("MULTIPLY".equals(opt))?{return?a?*?b; }?else?{return?a?/?b; }優化后:
private?int?calculate(String?opt)?{int?a?=?2;int?b?=?5;switch?(opt)?{case?"plus":return?a?+?b;case?"minus":return?a?-?b;case?"multiply":return?a?*?b;default:return?a?/?b;} }優點:可讀性高;當有條件不需要后可以直接刪除相應開關,更加直觀。
6. hibernate-validator
“Controller 層接口入參時不妨試試它,別再 if / else 一層層判斷了
”該校驗包在 Spring Boot 2.3.0 之前的 spring-boot-starter-web 依賴中已經自帶了,可以直接使用。
在 Spring Boot 2.3.0 之后,校驗包已經被獨立出來了,需要額外再引入依賴。
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId> </dependency>場景:接口入參需要進行大量的參數校驗判斷時
優化前:
優化后:
@Data public?class?DataDto?{@Min(value?=?1,?message?=?"id不能小于1")@NotNull(message?=?"id不能為空")private?Integer?id;@NotBlank(message?=?"姓名不能為空")private?String?name;@Email(message?=?"email無效")@NotNull(message?=?"email不能為空")private?String?email;@NotNull(message?=?"手機號不能為空")@Pattern(regexp?=?"^(13[0-9]|14[579]|15[0-3,5-9]|16[6]|17[0135678]|18[0-9]|19[89])\\d{8}$",?message?=?"手機號無效")private?String?phone; }使用 @Valid 進行校驗,校驗后的結果放入后面的 bindingResult 對象中。
BindingResult 必須緊跟著需要被校驗的參數對象。
@RestController public?class?DemoController?{@PostMapping("demo")public?String?testParameters(@RequestBody?@Valid?DataDto?dataDto,?BindingResult?bindingResult)?{if?(bindingResult.hasErrors())?{List<FieldError>?fieldErrors?=?bindingResult.getFieldErrors();return?fieldErrors.get(0).getDefaultMessage();}return?dataDto?+?"?is?ok!!!";}} name 傳空字符串我們可以來看看校驗的結果對象里面都有哪些信息
email 傳錯誤格式正常傳參當接口多了,每個接口如果都來個 BindingResult 也是個體力活兒,這時候就可以考慮全局異常了。
@ControllerAdvice public?class?RequestBadExceptionHandler?{@ResponseBody@ExceptionHandler(value?=?MethodArgumentNotValidException.class)public?String?methodArgumentException(MethodArgumentNotValidException?e)?{//?拿到ObjectError錯誤信息對象ObjectError?objectError?=?e.getBindingResult().getAllErrors().get(0);//?返回對象里的錯誤提示信息return?"參數錯誤:"?+?objectError.getDefaultMessage();}}去除 BindingResult
@PostMapping("demo") public?String?testParameters(@RequestBody?@Valid?DataDto?dataDto)?{return?dataDto?+?"?is?ok!!!"; } 傳入無效手機號正常傳參怎么樣,這樣的入參校驗是不是比 if / else 要更加優雅?
Hibernate Validator 官網說明:https://docs.jboss.org/hibernate/validator/6.0/reference/en-US/html_single/
以下列出一些常用的校驗注解
| @NotNull | 不為null |
| @NotEmpty | 不為 null 并且不為空字符串 |
| @NotBlank | 不為 null 并且包含至少一個非空白字符 |
| @Min | 最小值 |
| @Max | 最大值 |
| @Digits | 設定最大整數位數和最大小數位數 |
| @DecimalMin | 大于等于給定的值 |
| @DecimalMax | 小于等于給定的值 |
| @Past | 必須是過去的時間 |
| @PastOrPresent | 必須是過去的時間,包含現在 |
| @Future | 必須是將來的時間 |
| @FutureOrPresent | 當前或將來時間 |
| @PositiveOrZero | 正數或0 |
| 校驗是否符合Email格式 |
7. 策略模式
場景:不同條件下需要執行不同的操作
優化前:
public?Integer?count(Integer?a,?Integer?b,?String?opt)?{if?("PLUS".equals(opt))?{return?a?+?b;}?else?if?("MINUS".equals(opt)){return?a?-?b;}?else?if?("MULTIPLY".equals(opt))?{return?a?*?b;}?else?{return?a?/?b;} }優化后:
采用枚舉實現策略模式
public?interface?ArithmeticOperation?{/***?計算**?@param?a?待計算值*?@param?b?待計算值*?@return?計算結果*/int?calculate(int?a,?int?b);} public?enum?ArithmeticEnum?implements?ArithmeticOperation?{/***?加*/PLUS?{@Overridepublic?int?calculate(int?a,?int?b)?{return?a?+?b;}},/***?減*/MINUS?{@Overridepublic?int?calculate(int?a,?int?b)?{return?a?-?b;}},/***?乘*/MULTIPLY?{@Overridepublic?int?calculate(int?a,?int?b)?{return?a?*?b;}},/***?除*/DIVIDE?{@Overridepublic?int?calculate(int?a,?int?b)?{return?a?/?b;}};} public?Integer?count(Integer?a,?Integer?b,?String?opt)?{ArithmeticEnum?arithmeticEnum?=?ArithmeticEnum.valueOf(opt);return?arithmeticEnum.calculate(a,?b); }優點:這樣我們的代碼就很好地做到了橫向擴展,不用再寫一堆的 if / else 進行判斷,后期維護也變得更容易了。
用到策略模式的場景還有很多,比如訂單來源不同需要做不同操作,使用優惠券打折分折扣券和抵扣券……
最后
這里面的7種你平常都用到了哪些?我覺得還是挺好掌握的,快去看看自己代碼有哪里可以優化的迅速改起來吧!!!
有道無術,術可成;有術無道,止于術
歡迎大家關注Java之道公眾號
好文章,我在看??
總結
以上是生活随笔為你收集整理的7 种让 if / else 变得更加优雅的方式,你 pick 了吗?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: oracle 自定义函数
- 下一篇: 廖雪峰Java1-3流程控制-9brea