Java程式設計語言
java 是一種可以撰寫跨平台應用軟體的物件導向的程式設計語言,是由Sun Microsystems公司於1995年5月推出的Java程式設計語言和Java平台(即JavaEE(j2ee) , JavaME(j2me), JavaSE(j2se))的總稱。
我們知道Java 8 增加了一些很有用的API, 其中一個就是Optional. 如果對它不稍假探索, 只是輕描淡寫的認為它可以優雅的解決NullPointException 的問題, 於是程式碼就開始這麼寫了
Optional<User> user = …… if (user.isPresent()) { return user.getOrders(); } else { return Collections.emptyList(); }
那麼不得不說我們的思維仍然是在原地踏步, 只是本能的認為它不過是User 實例的包裝, 這與我們之前寫成
User user = ….. if (user != null) { return user.getOrders(); } else { return Collections.emptyList(); }
實質上是沒有任何分別. 這就是我們將要講到的使用好Java 8 Optional 類型的正確姿勢.
在裡約奧運之時, 新聞一再提起五星級紅旗有問題, 可是我怎麼看都看不出來有什麼問題, 後來才道是小星星膜拜中央的姿勢不對.因此我們千萬也別對自己習以為常的事情覺得理所當然, 絲毫不會覺得有何不妥, 換句話說當我們切換到Java 8 的Optional 時, 不能繼承性的對待過往null 時的那種思維,應該掌握好新的, 正確的使用Java 8 Optional 的正確姿勢.
直白的講, 當我們還在以如下幾種方式使用Optional 時, 就得開始檢視自己了
調用 isPresent() 方法時
調用 get() 方法時
Optional 類型作為類別/實例屬性時
Optional 類型作為方法參數時
isPresent() 與 obj 類型作為方法參數時
isPresent() 與 obj 類型作為方法參數時
isPresent() 與 obj 類型!而沒有 isPresent() 作鋪墊的 get() 調用在IntelliJ IDEA 中會收到告警
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. (调用 Optional.get() 前不事先用 isPresent() 检查值是否可用. 假如 Optional 不包含一个值, get() 将会抛出一个异常)
把Optional 類型用作屬性或是方法參數在IntelliJ IDEA 中更是強力不推薦的
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 的类型作为字段或方法参数都是不可取的. Optional 只设计为类库方法的, 可明确表示可能无值情况下的返回类型. Optional 类型不可被序列化, 用作字段类型会出问题的)
我們所以Optireee真正可依賴的應該是除了 isPresent() 和 get() 的其他方法:
public Optional map(Function super T, ? extends U> mapper)
public T orElse(T orElse )
public T orElseGet(Supplier extends T> other)
public void ifPresent(Consumer super T> consumer)
public Optional 的我略有自信它們大概用頻度對上面的方法排了一下序. 先又不得不提一下Optional 的三種構造方式: Optional.of(obj), Optional.ofNullable(obj) 和明確的 Optional.empty() Optional.of(obj): 它要求傳入的obj 不能是null 值的, 否則還沒開始進入角色就倒在了 NullPointerException 異常上了. Optional.ofNullable(objofNullable(obj): 它以一種智能的, 寬容的方式來構造一個Optional 實例. 來者不拒, 傳null 進到就得到 Optional.empty(), 非null 就調用 Optional.of(obj). 那是不是我們只要用 Optional.of(obj). 那是不是我們只要用 Optional.ofNullable (obj) 一勞永逸, 以不變應二變的方式來構造Optional 實例就行了呢? 那也未必, 否則 Optional.of(obj) 何必如此暴露呢, 私有則可? 我本人的觀點是: 1 . 當我們非常非常的明確將要傳給 Optional.of(obj) 的 obj 參數不可能為null 時, 例如它是一個剛 new 出來的物件(Optional.of(new User(...))), 或者是非null 常數時; 2. 當想為 obj 斷言不為null 時, 即我們想在萬一 obj 為null 立即報告 NullPointException 異常, 立即修改, 而不是隱藏空指針異常時, 我們應該果斷的用Optional.of(obj) 來建構Optional 實例, 而不讓任何不可預期的null 值有可乘之機隱身於Optional 中. 現在才開始怎麼去使用一個已有的Optional 實例, 假定我們有一個實例Optional 存在才对它做点什么 map 函数隆重登场 当 user.isPresent() 为真, 获得它关联的 orders, 为假则返回一个空集合时, 我们用上面的 orElse, orElseGet 方法都乏力时, 那原本就是 map 函数的责任, 我们可以这样一行 map 是可能无限级联的, 比如再深一层, 获得用户名的大写形式 这要搁在以前, 每一级调用的展开都需要放一个 null 值的判断 针对这方面 Groovy 提供了一种安全的属性/方法访问操作符 ?. Swift 也有类似的语法, 只作用在 Optional 的类型上. 用了 isPresent() 处理 NullPointerException 不叫优雅, 有了 orElse, orElseGet 等, 特别是 map 方法才叫优雅. 其他几个, filter() 把不符合条件的值变为 empty(), flatMap() 总是与 map() 方法成对的, orElseThrow() 在有值时直接返回, 无值时抛出想要的异常. 一句话小结: 使用 Optional 时尽量不直接调用 Optional.get() 方法, Optional.isPresent() 更应该被视为一个私有方法, 应依赖于其他像 Optional.orElse(), Optional.orElseGet(), Optional.map() 等这样的方法. 最后, 最好的理解 Java 8 Optional 的方法莫过于看它的源代码 java.util.Optional, 阅读了源代码才能真真正正的让你解释起来最有底气, Optional 的方法中基本都是内部调用 isPresent() 判断, 真时处理值, 假时什么也不做. 以上就是使用 Java8 Optional 的正确姿势的内容,更多相关内容请关注PHP中文网(www.php.cn)!return user.orElse(null); //而不是 return user.isPresent() ? user.get() : null;
return user.orElse(UNKNOWN_USER);
return user.orElseGet(() -> fetchAUserFromDatabase()); //而不要 return user.isPresent() ? user: fetchAUserFromDatabase();
user.ifPresent(System.out::println);
//而不要下边那样
if (user.isPresent()) {
System.out.println(user.get());
}
return user.map(u -> u.getOrders()).orElse(Collections.emptyList())
//上面避免了我们类似 Java 8 之前的做法
if(user.isPresent()) {
return user.get().getOrders();
} else {
return Collections.emptyList();
}
return user.map(u -> u.getUsername())
.map(name -> name.toUpperCase())
.orElse(null);
User user = .....
if(user != null) {
String name = user.getUsername();
if(name != null) {
return name.toUpperCase();
} else {
return null;
}
} else {
return null;
}
user?.getUsername()?.toUpperCase();