Optional類是Java8新增的一個類,其做用能夠有效避免空指針異常。java
Optional類的代碼比較簡單,很容易就能看懂,其實質就是一個輔助類,把須要處理的對象作了一層包裝,而後再使用Optional中的方法時,能夠有效得判斷處理對象是否爲空,從而作出正確判斷。json
接下來咱們看下如何使用Optional。數據結構
建立Optional有3種方式:iphone
若是可以確保入參必定不爲null,能夠用Optional.of
,由於在Optional.of
內部會判斷是否爲null,若是是null則拋出異常。函數
若是不太肯定入參是否爲null,能夠用Optional.ofNullable
。post
對象建立好了,接下來看看如何使用。學習
isPresent()方法判斷處理對象是否爲null,不爲null返回true,源碼以下:ui
public boolean isPresent() { return value != null; }
ifPresent方法有一個入參ifPresent(Consumer<? super T> consumer)
,它的意思是若是對象不爲null,則運行consumer進行處理,有點相似回調函數。this
String s = "hello"; Optional<String> optional = Optional.of(s); if(optional.isPresent()) { System.out.println("the value is " + optional.get()); }
一樣能夠寫成:指針
optional.ifPresent((val) -> { System.out.println("the value is " + val); });
filter是對處理對象進行判斷,若是判斷爲true,則返回當前Optional,若是爲false則返回一個空的Optional對象,其源碼以下:
public Optional<T> filter(Predicate<? super T> predicate) { Objects.requireNonNull(predicate); if (!isPresent()) return this; else return predicate.test(value) ? this : empty(); }
filter方法有個參數:Predicate,這是一個函數式接口,所以咱們可使用Lambda表達式來處理。
String s = "hello"; Optional<String> optional = Optional.of(s); boolean exist = optional .filter(val -> "hello1".equals(val)) .isPresent(); System.out.println(exist); // false
map方法的做用能夠簡單理解成從處理對象中取出其它對象,而後返回一個新的Optional。以下代碼所示:
public class OptionalMapTest { static class Goods { private String goodsName; private Company company; ...getter setter } static class Company { private String companyName; ...getter setter } public static void main(String[] args) { Company company = new Company(); company.setCompanyName("Apple"); Goods goods = new Goods(); goods.setGoodsName("iphoneX"); goods.setCompany(company); Optional<Goods> optional = Optional.of(goods); String companyName = optional // 從goods中取出Company,返回一個新的Optional<Company> .map(goodsObj -> goodsObj.getCompany()) // 從company中取出companyName,返回一個新的Optional<String> .map(companyObj -> companyObj.getCompanyName()) // 獲得companyName .get(); System.out.println(companyName); } }
什麼狀況下該使用flatMap呢,咱們把Goods中的的Company對象改爲Optional<Company>
。
static class Goods { private String goodsName; private Optional<Company> company; ...getter setter }
此時下面這段代碼會編譯報錯
String companyName = optional // 從goods中取出Company,返回一個新的Optional<Company> .map(goodsObj -> goodsObj.getCompany()) // !!這裏會報錯 // 從company中取出companyName,返回一個新的Optional<String> .map(companyObj -> companyObj.getCompanyName()) // 獲得companyName .get();
主要是這行代碼optional.map(goodsObj -> goodsObj.getCompany())
。由於此時返回的是一個Optional<Optional<Company>>
對象。
而咱們須要的是Optional<Company>
對象,這個時候就應該用到flatMap了,只要把optional.map(goodsObj -> goodsObj.getCompany())
改爲optional.flatMap(goodsObj -> goodsObj.getCompany())
便可。
String companyName = optional // 從goods中取出Company,返回一個新的Optional<Company> .flatMap(goodsObj -> goodsObj.getCompany()) // 從company中取出companyName,返回一個新的Optional<String> .map(companyObj -> companyObj.getCompanyName()) // 獲得companyName .get();
簡單的理解就是:
String s = null; Optional<String> optional = Optional.ofNullable(s); System.out.println(optional.get()); // 拋出java.util.NoSuchElementException: No value present
針對這種狀況,有幾種處理方式
方式1:使用isPresent()
String s = null; Optional<String> optional = Optional.ofNullable(s); if (optional.isPresent()) { System.out.println(optional.get()); } else { System.out.println("默認值"); }
方式2:使用orElse(默認值)
String s = null; Optional<String> optional = Optional.ofNullable(s); System.out.println(optional.orElse("默認值"));
orElse(默認值)的意思是若是Optional中的值爲null,則返回給定的默認值。
方式3:使用orElseGet(Supplier)
String s = null; Optional<String> optional = Optional.ofNullable(s); System.out.println(optional.orElseGet(() -> "默認值"));
orElse(Supplier)的意思是若是Optional中的值爲null,則執行指定的Supplier接口,因爲Supplier是個函數式接口,所以可使用Lambda表達式代替。
由此看來,方式2和方式3的處理是比較優雅的。
方式2和方式3的區別在於,方式3能夠延遲返回,只有值爲null的狀況下才會觸發() -> "默認值"
,從而避免生成無用對象,方式2無論如何都生成了"默認值"這個字符串對象。下面的例子能夠說明:
String s = "1"; Optional<String> optional = Optional.ofNullable(s); System.out.println(optional.orElse(getDefault()));
打印:
生成了字符串對象 1
即便Optional中的值不爲null,但仍是執行了getDefault(),這徹底不必,再來看下使用orElseGet
String s = "1"; Optional<String> optional = Optional.ofNullable(s); System.out.println(optional.orElseGet(() -> getDefault()));
打印:1
接着再看下orElseThrow,若是值爲null,則直接拋出異常
String s = null; Optional<String> optional = Optional.ofNullable(s); System.out.println(optional.orElseThrow(() -> new NullPointerException("不能爲空")));
{ "user": { "age": 20 ,"name": "Jim" ,"address": { "province": "浙江省" ,"postcode": "111111" } } }
假設有這樣一個json字符串,如今要獲取postcode信息。若是不用Optional的話,要寫各類if…else語句,還要判斷字段是否存在。
String postcode = "unknown"; JSONObject user = jsonObj.getJSONObject("user"); if (user != null) { JSONObject address = user.getJSONObject("address"); if (address != null) { String code = address.getString("postcode"); if (postcode != null) { postcode = code; } } } System.out.println(postcode);
可是用Optional能夠這樣寫:
JSONObject jsonObj = JSON.parseObject(json); String postcode = Optional.ofNullable(jsonObj) .flatMap(jsonObject -> Optional.ofNullable(jsonObject.getJSONObject("user"))) .flatMap(jsonObject -> Optional.ofNullable(jsonObject.getJSONObject("address"))) .flatMap(jsonObject -> Optional.ofNullable(jsonObject.getString("postcode"))) .orElse("unknown"); System.out.println(postcode);
注意,這裏要使用flatMap,由開發者手動返回一個Optional對象,若是使用map的話則返回Optional<Optional<JSONObject>>
。
最後一句.orElse("unknown")表示若是一路走下來沒有找到值,則返回一個默認值。
Optional的優點是處理嵌套數據結構,如這裏的json數據。假如這段json數據結構不是完整的,postcode字段不存在,或者整個address字段都不存在,在沒法保證嵌套數據中的值是否存在的狀況下,使用Optional是個不錯的選擇。它都能確保有個正確的返回值。
本篇主要介紹了Optional類的用法,同時演示瞭如何使用Optional處理嵌套數據。
按期分享技術乾貨,一塊兒學習,一塊兒進步!