原文地址
Optional的代碼相對更加簡潔,當代碼量較大時抛猖,我們很容易忘記進行null判定乔煞,但是使用Optional類則會避免這類問題。
下面這是一個嵌套的 if 判斷,業(yè)務(wù)邏輯是從 httpRequst 中獲取 X-Auth-Token 的值忍啤。邏輯是如果 header中有值則從 header 中取值否則從 cookie 中取值,取到值后調(diào)用一個 http 遠程接口 獲取用戶信息,獲取不到則報“獲取用戶信息失敗”,如果 token 都不存在則直接返回 httpRespons 為 401-NoAuth
這下面是之前同事寫的代碼
if 嵌套代碼
if (methodNeedAuth) {
//***身份驗證
String token = request.getHeader("X-Auth-Token");
if (StringUtils.isEmpty(token)) { // 如果 header 中沒有 X-Auth-Token 則從 cookie 中取
Cookie[] cookies = request.getCookies();
if (cookies == null || cookies.length == 0) { //cookie 為 null
return returnNoAuthResult(response);
} //這個地方判空,否則下面的 Arrays.stream 回報空指針異常
token = Arrays.stream(cookies).filter(cookie ->
"X-Auth-Token".equals(cookie.getName())
).collect(Collectors.toList()).get(0).getValue();
if (token == null) { // cookie 有值但是 cookie 中沒有 X-Auth-Token
return returnNoAuthResult(response);
}
}
if (!StringTool.isNullOrEmpty(token)) {
userInfo = userService.getUserInfoByToken(token);
}
if (userInfo == null || StringTool.isNullOrEmpty(userInfo.getUser_id())) {
return returnNoAuthResult(response);
}
}
Optional 規(guī)避 if 嵌套
if (methodNeedAuth) {
//***身份驗證
String token = Optional.ofNullable(request.getHeader("X-Auth-Token")).orElseGet(() ->
getTokenFromCookie(request) //提取出一個方法
);
userInfo = Optional.ofNullable(token).map(Try.of(t ->
userService.getUserInfoByToken(t))
).orElse(null);
if (userInfo == null || StringTool.isNullOrEmpty(userInfo.getUser_id())) {
response.sendError(401, "no auth");
return false;
}
}
/**
* 從 cookie 中獲取 token
*/
private String getTokenFromCookie(HttpServletRequest request) {
Cookie[] cookies = Optional.ofNullable(request.getCookies()).orElse(new Cookie[0]); // Optional 強制賦默認值,cookies一定不為 null
String cookie = Arrays.stream(cookies).filter(item ->
"X-Auth-Token".equals(item.getName())
).findFirst().map(Cookie::getValue).orElse(null);
return cookie;
}
小結(jié)
Java8 Optional 的常規(guī)用法
Java8 的 Optional 可以規(guī)避所有的空指針異常問題么?答案當然是否定的, Optional<T>()
也是對象,他也會為 null, 所以也有可能報空指針異常喲仙辟。
Optional 的三種構(gòu)造方式: Optional.of(obj), Optional.ofNullable(obj) 和明確的 Optional.empty()
- Optional.of(obj): 它要求傳入的 obj 不能是 null 值的, 否則還沒開始進入角色就倒在了 NullPointerException 異常上了.
- Optional.ofNullable(obj): 它以一種智能的, 寬容的方式來構(gòu)造一個 Optional 實例. 來者不拒, 傳 null 進到就得到 Optional.empty(), 非 null 就調(diào)用 Optional.of(obj).
那是不是我們只要用 Optional.ofNullable(obj) 一勞永逸, 以不變應(yīng)二變的方式來構(gòu)造 Optional 實例就行了呢? 那也未必, 否則 Optional.of(obj) 何必如此暴露呢, 私有則可?
我本人的觀點是:
- 當我們非常非常的明確將要傳給 Optional.of(obj) 的 obj 參數(shù)不可能為 null 時, 比如它是一個剛 new 出來的對象(Optional.of(new User(...))), 或者是一個非 null 常量時;
- 當想為 obj 斷言不為 null 時, 即我們想在萬一 obj 為 null 立即報告 NullPointException 異常, 立即修改, 而不是隱藏空指針異常時, 我們就應(yīng)該果斷的用 Optional.of(obj) 來構(gòu)造 Optional 實例, 而不讓任何不可預計的 null 值有可乘之機隱身于 Optional 中.
Java8 Optional需要小心的地方
- Reports calls to java.util.Optional.get() without first checking with a isPresent() call if a value is available. If the Optional does not contain a value, get() will throw an exception. (調(diào)用 Optional.get() 前不事先用 isPresent() 檢查值是否可用. 假如 Optional 不包含一個值, get() 將會拋出一個異常)
- Reports any uses of java.util.Optional<T>, java.util.OptionalDouble, java.util.OptionalInt, java.util.OptionalLong or com.google.common.base.Optional as the type for a field or a parameter. Optional was designed to provide a limited mechanism for library method return types where there needed to be a clear way to represent “no result”. Using a field with type java.util.Optional is also problematic if the class needs to be Serializable, which java.util.Optional is not. (使用任何像 Optional 的類型作為字段或方法參數(shù)都是不可取的. Optional 只設(shè)計為類庫方法的, 可明確表示可能無值情況下的返回類型. Optional 類型不可被序列化, 用作字段類型會出問題的)
一句話小結(jié): 使用 Optional 時盡量不直接調(diào)用 Optional.get() 方法, Optional.isPresent() 更應(yīng)該被視為一個私有方法, 應(yīng)依賴于其他像 Optional.orElse(), Optional.orElseGet(), Optional.map() 等這樣的方法.