簡述
Optional類是java8中引入的一個非常有用的類,主要用處是解決編程中的空指針異常,本質上,這是一個包含有可選值的包裝類,這意味着 Optional 類既可以含有對象也可以為空。Optional 是 Java 實現函數式編程的強勁一步,並且幫助在范式中實現。
空指針異常的麻煩
在java8之前,任何訪問對象方法或屬性的調用都有可能導致空指針異常,例如:
String isocode = user.getAddress().getCountry().getIsocode().toUpperCase();
這行代碼如果我們需要確保不觸發異常,我們就要寫成:
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實例
使用empty()創建空實例
Optional<User> emptyOpt = Optional.empty();
嘗試訪問emptyOpt變量的值會導致NoSuchElementException
使用of()或ofNullable()方法創建包含值的Optional,不同之處在於:如果你把 null 值作為參數傳遞進去,of() 方法會拋出 NullPointerException
Optional<User> opt1 = Optional.of(user);
Optional<User> opt1 = Optional.ofNullable(user);
訪問Optional對象的值
使用get()方法獲取Optional的值
Optional<User> opt1 = Optional.of(user);
User tmp = opt1.get();
get方法會在值為null的時候拋出異常,我們可以用ifPresent()方法驗證值是否為空
返回默認值
orElse()方法可以在創建實例時就指定返回的默認值
User user = null; User user2 = new User("anna@gmail.com", "1234"); User result = Optional.ofNullable(user).orElse(user2);
因為user是空,所以此時我們想獲取result的值的話會得到user2
我們也可以使用orElseGet(),如果沒有值,它會執行作為參數傳入的 Supplier(供應者) 函數式接口,並將返回其執行結果
User result = Optional.ofNullable(user).orElseGet( () -> user2);
不同的是使用orElse的話無論創建的值是否為空,都會orElse里的代碼,如果里面有創建新的實例,這會對性能產生很大影響
另外我們可以使用orElseThrow(),它會在對象為空的時候拋出異常,而不是返回備選的值
User result = Optional.ofNullable(user) .orElseThrow( () -> new IllegalArgumentException());
此時如果user為空,會拋出我們定義的異常IllegalArgumentException
轉換值
我們可以使用map方法,將 Optional里的元素進行轉換
User user = new User("anna@gmail.com", "1234"); String email = Optional.ofNullable(user) .map(u -> u.getEmail()).orElse("default@gmail.com");
注意無論是user為null,還是user里的Email為空,都會觸發返回orElse里的默認值,這也就Optional的map操作的鏈式調用的精髓,我們可以不斷的接着寫map,無需一次次地判斷是否為空
注意如果當對象發生Optinoal嵌套的時候,我們需要使用flatMap方法,詳細請看:https://blog.csdn.net/qq_35634181/article/details/101109300
過濾值
filter()接受一個Predicate參數,返回測試結果為 true 的值
用法和stream的filter一模一樣,例如我們可以檢查用戶的郵箱是否帶@
User user = new User("anna@gmail.com", "1234"); Optional<User> result = Optional.ofNullable(user) .filter(u -> u.getEmail() != null && u.getEmail().contains("@"));
對原來if的改進
對於User類我們對其進行重構,使其getter方法返回Optional類

public class User { private Address address; public Optional<Address> getAddress() { return Optional.ofNullable(address); } // ... } public class Address { private Country country; public Optional<Country> getCountry() { return Optional.ofNullable(country); } // ... }
上面的嵌套結構可以用下面的圖來表示:
之前冗雜的if判斷我們就可以改成這樣:
String result = Optional.ofNullable(user) .flatMap(u -> u.getAddress()) .flatMap(a -> a.getCountry()) .map(c -> c.getIsocode()) .orElse("default");
也可以簡寫成這樣:
String result = Optional.ofNullable(user)
.flatMap(User::getAddress)
.flatMap(Address::getCountry)
.map(Country::getIsocode)
.orElse("default");
Reference
https://blog.csdn.net/wwe4023/article/details/80760416
https://blog.csdn.net/qq_35634181/article/details/101109300