1. 如果接口的返回值有可能是null,請用Optional封裝
public Optional<User> getUser() { return Optional.ofNullable(user); }
return getUser().orElse(defaultUser); return getUser().map(u -> u.getOrders()).orElse(Collections.emptyList()); |
---|
其他使用方法參考:http://unmi.cc/proper-ways-of-using-java8-optional/
好處:
- 優雅,下游不用寫惡心的if-else判斷
- 安全:告知接口的使用方返回值可能為null,需要處理,以避免代碼缺陷
- 文檔化:接口中可能為空的值文檔化
2. 如果接口返回一個集合(list或set),可能一個Stream工廠是更好的選擇
public Stream<UserBo> getUsers() { return userList.stream(); }
public Stream<UserDto> getUsers(Stream<UserBo> users) { return users.map(UserDto::new); }
public List<UserVo> getUsers(Stream<UserDto> users) { return users.map(UserVo::new).collect(toList()); } |
---|
優點:
- 封裝:很好地封裝了內部實現的數據結構,僅暴露一個Stream接口,不用糾結返回Set還是List
- 緩求值:減少占用的存儲空間,有利於運行時產生更高效率的代碼(中間不用產生List<UserDto>對象了)
3. 使用Either取代拋出Exception
public Either<ErrorDtoException, UserDto> addUser(String userName) { if (exist(userName)) { return Either.left(new ErrorDtoException("username is exist")); } UserBo UserBo = saveUser(userName); return Either.right(new UserDto(userBo); }
return addUser("myName").fold(e -> e.getMessage(), userDto -> userDto.getName()); |
---|
更多Either的API可參考源碼
優點:
- 消除副作用:拋出異常的行為本身就是一種副作用,會導致程序路徑偏離正軌(進入異常的流程)。
- 優雅:在返回值里表明錯誤並作出響應,這樣就不需要打斷程序的一般流程了。
4. 如果接口會拋出非受檢異常或下游不那么關注的異常,可使用Try封裝
public Try<Integer> divide(Integer a, Integer b) { return Try.of(() -> a / b); }
return divide(a, b).orElseMap(throwable -> defaultValue); |
---|
更多Try的API可參考源碼
優點和Either類似
https://github.com/javadeep/common-functional/blob/master/functional-lang/src/main/java/com/javadeep/functional/lang/control/retry/Retrys.java以及https://github.com/javadeep/common-functional/blob/master/functional-lang/src/main/java/com/javadeep/functional/lang/control/validator/FunctionalValidator.java中的實現均用到了Try數據結構,可深入體會下。