Java8以前咱們在寫代碼的時候,常常會遇到返回null的狀況,若是這種狀況不加以判斷,你就會碰到NullPointerException(NPE)。而在Java8中,Optional類型是一種更好的表示缺乏返回值的形式。java
首先來看一段代碼,這多是之前大多數人的寫法web
private void getIsoCode( User user){
if (user != null) {
Address address = user.getAddress();
if (address != null) {
Country country = address.getCountry();
if (country != null) {
String isocode = country.getIsocode();
if (isocode != null) {
isocode = isocode.toUpperCase();
}
}
}
}
}
複製代碼
而當咱們有了Optional以後,上面的代碼就能夠縮減很大一部分,答案我會在後面給出。數據庫
我見過有人的寫法是這樣的安全
Optional<T> optionalValue = ... ;
optionalValue.get().someMethod();
或者
if(optionalValue.isPresent()) {
optionalValue.get().someMethod();
}
複製代碼
它並不比下面的方式安全app
T value = ... ;
value.someMethod();
或者
if(value != null) {
value.someMethod();
}
複製代碼
若是你在你的代碼中出現了上面使用Optional的片斷,那麼你該好好優化下了。函數
其實高效使用Optional的關鍵在於,使用一個 接受正確值或者返回另外一個替代值 的方法。性能
// 建立一個空的Optional實例
public static<T> Optional<T> empty() {
Optional<T> t = (Optional<T>) EMPTY;
return t;
}
// 根據傳入的值建立一個非空的實例, value不能爲空,不然拋出NPE
public static <T> Optional<T> of(T value) {
return new Optional<>(value);
}
// 根據傳入的值建立實例,value能夠爲空
public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}
複製代碼
上面的三個方法就是咱們構造Optional的途徑,能夠看到實際上Optional是對value的封裝。
須要注意的是ofNullable
和 of
的區別,推薦使用ofNullable
方法優化
boolean isPresent()
判斷value是否存在spa
Optional filter(Predicate predicate)
判斷value是否知足條件code
Optional<U> map(Function<? super T, ? extends U> mapper)
對其中的value執行一個函數,將其變成另外一個值。返回的值會被Optional.ofNullable封裝
Optional<U> flatMap(Function<? super T, Optional<U>> mapper)
也是對其中的value執行一個函數,注意和map的區別在於,執行這個函數返回的值是Optional類型,返回的值不會被封裝。
orElse(T other)
當value存在時,返回value,不存在時返回other
orElseGet(Supplier<? extends T> other)
和orElse同樣,只是這裏的參數是經過傳入的function來決定的
T orElseThrow
當value存在時,返回value,不存在時拋出異常
開頭給出的代碼就能夠被優化爲下面的代碼
String isoCode = Optional.ofNullable(user)
.map(User::getAddress) //Optional<Address>
.map(Address::getCountry) //Optional<Country>
.map(Country::getIsocode) // Optional<String>
.orElse("empty");
複製代碼
不過有一點須要注意的是orElse和orElseGet的區別在於,不管是否知足條件orElse中的方法始終會被執行,而orElseGet中的只有當value爲空時纔會執行。
Optional.ofNullable(user)
.map(User::getAddress)
.map(Address::getCountry)
.map(Country::getIsocode)
.orElse(getIsoCode());
複製代碼
你可能以爲沒什麼,可是若是你的業務中獲取這個值要去數據庫查詢,那麼每一次只要運行這個代碼就都要去查詢,這樣就形成了沒必要要的性能損失了,仍是一個很大的問題的。