在Java8以前, 若是須要對一個變量作一次 null 檢查, 一般會像下面這樣寫app
T t = service1.query(); if (t != null) { K k = service2.update(t); if (k != null) { U u = service3.save(k); } }
若是業務比較複雜, 可能會像上面那樣, 使用 if 語句進行多層嵌套, 後期難以擴展。ide
在Java8中新引入了一個 Optional 類, Optional 類會對可能爲 null 值的變量進行建模, 這樣你就沒必要直接將 null 賦值給變量, 也就沒必要像上面那樣進行多層嵌套檢查。函數
在正式介紹 Optional 類的 API以前, 先引入一些實體類, 後面的代碼示例會常常用到它們。測試
@Data public class Person { private Car car; private int age; public Optional<Car> getCar() { return Optional.ofNullable(car); } } @Data public class Car { private Insurance insurance; public Optional<Insurance> getInsurance() { return Optional.ofNullable(insurance); } } @Data public class Insurance { private String name; }
Optional 類提供了三種方式來建立 Optional 對象this
@Test public void test1() { //聲明一個空的optional Optional<Car> c1 = Optional.empty(); //根據一個非空的值建立optional, 若是傳入的值是null,會拋出空指針異常 Optional<Car> c2 = Optional.of(new Car()); //可接受null的Optional Optional<Object> c3 = Optional.ofNullable(null); }
flatMap()和map()都是在指定值存在時, 就對該值執行提供的 mapping 函數調用, 返回一個 Optional 類型的值, 不然就返回一個空的 Optional 對象。spa
注意 flatMap() 方法的轉換函數是 Function<? super T, Optional<U>> mapper , 這個特性和前面介紹的 Stream 類的 flatMap() 很像。指針
查看一下 Optional 類的源碼, flatMap() 會將 Optional<T> 中的 T 轉換成 Optional<U>, 再將轉換後的 Optional<U> 直接做爲方法返回值返回。code
@Test public void test2() { Optional<Person> person = Optional.ofNullable(new Person()); String name = person.flatMap(Person::getCar).flatMap(Car::getInsurance).map(Insurance::getName).orElse("哪吒之魔童降世"); System.out.println(name); //result: 哪吒之魔童降世 }
上面的代碼示例中, 由於 Person 實體類中 car 屬性是一個 null 值, 因此 person.flatMap(Person::getCar) 這個操做會獲得一個空的Optional 對象。orm
這樣就致使了後面的 flatMap() 和 map() 兩次轉換都返回一個空的 Optional 對象。orElse() 方法的含義是若是有值則將其返回,不然返回一個默認值。因此最後的輸出結果是默認值 哪吒之魔童降世 。對象
在實際業務中, 你能夠像下面這樣將 Optional 做爲方法入參和返回值使用
@Test public void test3() { Optional<Insurance> insurance1 = find(Optional.of(new Person()), Optional.empty()); System.out.println(insurance1);//result: Optional.empty Optional<Insurance> insurance2 = find(Optional.of(new Person()), Optional.of(new Car())); System.out.println(insurance2);//result: Optional[Insurance(name=null)] } public Optional<Insurance> find(Optional<Person> person, Optional<Car> car) { return person.flatMap(p -> car.map(c -> find(p, c))); } private Insurance find(Person p, Car c) { return new Insurance(); }
@Test public void test4() { Optional.of("攀登者").filter(i -> i.length() < 4).ifPresent(System.out::println);//打印: 攀登者 Optional.<String>empty().filter(i -> i.length() < 4).ifPresent(System.out::println);//沒有輸出 }
下面是一個測試示例, 到本地去運行看下輸出結果, 它能夠幫你從新理解一下前面介紹的幾個 API 的用法。
@Test public void test5() { System.out.println(getCarInsuranceName(Optional.empty(), 8));//result: 命運之夜 Person p = new Person(); p.setAge(10); System.out.println(getCarInsuranceName(Optional.of(p), 8));//result: 命運之夜 Insurance insurance = new Insurance(); insurance.setName("知否知否"); Car car = new Car(); car.setInsurance(insurance); p.setCar(car); System.out.println(getCarInsuranceName(Optional.of(p), 8));//result: 知否知否 } //找出年齡大於或者等於 minAge 參數的 Person 所對應的保險公司列表。 public String getCarInsuranceName(Optional<Person> person, int minAge) { return person.filter(p -> p.getAge() >= minAge).flatMap(Person::getCar).flatMap(Car::getInsurance).map(Insurance::getName).orElse("命運之夜"); }
一般在因爲某種因素下, 函數沒法正確返回某個值, 常見的作法就是使用 try/catch 語句處理返回一個null值, 或者不作任何處理直接拋出一個異常。
若是函數沒法正確返回某個值, 且你不須要它拋出異常, 而是要它返回一個默認值, 那麼 Optional 能夠幫您更優雅的實現
@Test public void test6() { String value = "test"; Integer res = Optional.of(value).flatMap(this::str2Int).filter(i -> i > 0).orElse(0); System.out.println(res);//result: 0 } private Optional<Integer> str2Int(String str) { try { //若是能正確解析, 就將其封裝在 Optional 中返回 return Optional.of(Integer.valueOf(str)); } catch (NumberFormatException ex) { //若是解析發生異常, 就返回一個空的 Optional return Optional.empty(); } }
上面的代碼清單, Integer.valueOf() 會在入參不是一個整型數值時, 拋出 NumberFormatException , 咱們這裏對它作了處理, 當解析發生異常時, 就返回一個空的 Optional 對象。
上面的用例只有在 value 變量是大於零的整型數值時, 纔會輸出 value 變量的值, 不然, 輸出結果都是默認值 0。
最後, 來一張大圖
做者:張小凡
出處:https://www.cnblogs.com/qingshanli/ 本文版權歸做者和博客園共有,歡迎轉載,但未經做者贊成必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接,不然保留追究法律責任的權利。若是以爲還有幫助的話,能夠點一下右下角的【推薦】。