Java8中的Optional操做

做者:湯圓java

我的博客:javalover.ccgit

前言

官人們好啊,我是湯圓,今天給你們帶來的是《Java8中的Optional操做》,但願有所幫助,謝謝github

文章純屬原創,我的總結不免有差錯,若是有,麻煩在評論區回覆或後臺私信,謝啦

最近看到有幾個粉絲了(竊喜),多的話我也不說了,歡迎加入咱們的榮華富貴你們庭數據庫

簡介

目的:Optional的出現主要是爲了解決null指針問題,也叫NPE(NullPointerException)app

外形:Optional外形酷似容器(其實它就是一個容器),只是這個容器比較特殊,由於它只能存放一個對象,運氣很差的話這個對象仍是個nullide

操做:Optional從操做上來看,又跟前面的Stream流式操做很像,好比過濾filter - 提取map等函數

下面咱們用比較簡單的例子來對比着看下,Optional的一些基礎用法this

先來看下目錄編碼

目錄

  1. Optional是什麼
  2. 沒它 VS 有它
  3. 核心操做
  4. 應用

正文

1. Optional是什麼

Optional是一個容器,只能存放一個對象(可爲null)spa

Optional的出現是

  • 一個是爲了解決NPE問題(阿里開發手冊也有提到這一點,點擊可直接下載,官方連接)
  • 另外一個是爲了代碼更加清晰可讀,由於Optional這個名字的靈感就是來自英文optional(可選的),意思就是說這個對象能夠爲空,能夠不爲空

2. 沒它 VS 有它

下面咱們用舊代碼和新代碼來對比着看(所謂的新舊是以Java8爲分割線)

案例1:現有C類,咱們要提取C.name屬性

public class OptionalDemo {
    private static final String DEFAULT_NAME = "javalover";

    public static void main(String[] args) {
      // 傳入null,以身試法  
      getName(null);
    }
    // 取出c.name
    public static void getName(C c){
        // 舊代碼 Java8以前
        String name = (c!=null ? c.getName() : DEFAULT_NAME);
        System.out.println("old: "+name);
        // 新代碼 Java8以後(下面的三個操做方法後面會介紹,這裏簡單瞭解下)
        String nameNew = Optional
                            // 工廠方法,建立Optional<C>對象,若是c爲null,則建立空的Optional<C>對象
                            .ofNullable(c)
                            // 提取name,這裏要注意,即便c==null,這裏也不會拋出NPE,而是返回空的Optional<String>,因此在處理數據時,咱們不須要擔憂空指針異常
                            .map(c1->c1.getName())
                            // 獲取optional的屬性值,若是爲null,則返回給定的實參DEFAULT_NAME
                            .orElse(DEFAULT_NAME);

        System.out.println("new: "+nameNew);
    }
}
class C{
    private String name;

    public C(String name) {
        this.name = name;
    }
  // 省略getter/setter
}

乍一看,好像Java8以前的舊代碼更合適啊,只須要一個三目運算符

再看Optional操做,發現並無那麼簡潔

是這樣的,若是隻是一層判斷,那普通的if判斷作起來更方便;

可是若是嵌套兩層呢,好比b.getC().getName()?

下面咱們就看下,兩層嵌套會怎麼樣

例子2:現多了一個B類(依賴C類),咱們要從對象B中提取C的屬性name,即b.getC().getName()

B依賴C

public static void getName2(B b){
        // 舊代碼
        String name = (b!=null ? ( b.getC()!=null ? b.getC().getName() : DEFAULT_NAME) : DEFAULT_NAME);
        // 新代碼
        String nameNew = Optional
                .ofNullable(b)
                .map(b1->b1.getC())
                .map(c1->c1.getName())
                .orElse(DEFAULT_NAME);
        System.out.println(nameNew);
    }

class B{
    private C c;

    public B(C c) {
        this.c = c;
    }
  // 省略getter/setter
}

此次不論是乍一看,仍是一直看,都是Optional更勝一籌

例子3:現多了一個A類(依賴B類),咱們要提取a.getB().getC().getName()

A依賴B

等等等,省略號

意思到就行,反正要說的就是單從判空來看的話,Optional確定是好過三目運算符的(if/else這裏就不舉了,它的嵌套只會更多)

3. 核心操做

由於Optional主要是操做數據(相似數據庫操做),因此咱們這裏從數據的角度來進行分析

這裏咱們能夠分爲三種操做:保存數據、處理數據、獲取數據

相關操做

保存數據

  • (沒有默認值)public static <T> Optional<T> of(T value) :填充 T value 到 Optional 的屬性中;若是 value==null,則拋出NPE
  • (默認null)public static <T> Optional<T> ofNullable(T value) :填充 T value 到 Optional 的屬性中;若是引用爲null,則填充null
  • (構造一個空的Optional)public static<T> Optional<T> empty():單純地建立一個數據爲null的空Optional,即直接填充null到 Optional 的屬性中【不經常使用】

處理數據

  • (提取)public<U> Optional<U> map(Function<? super T, ? extends U> mapper) :提取Optional中屬性T的某個屬性值U,並將U填充到新的Optional中並返回
  • (過濾)public Optional<T> filter(Predicate<? super T> predicate) :過濾Optional中屬性T的某個屬性值,符合條件則將T填充到新的Optional中並返回
  • (扁平化提取)public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper):提取Optional中屬性T的某個屬性Optional<U>,直接返回

獲取數據

  • public T orElse(T other) :獲取數據,若是數據爲null,則返回T other
  • public T orElseGet(Supplier<? extends T> other):獲取數據,若是數據爲null,則經過函數式接口other返回一個新的數據T
  • public T get() :獲取數據,若是數據爲null,則報NPE【不經常使用】

上面這些操做中,不經常使用的就是get()和empty()

其餘的就不舉了,這裏主要說下map()和flatMap()

以下圖所示:

map()主要是提取Optional中的屬性C的屬性name,而後再包裝到新的Optional

輸入Optional<C>, 輸出Optional<String>(即Optional<c.name>)

map

String nameNew = Optional
                    .ofNullable(c)
                    .map(c1->c1.getName())
                    .orElse("xxx");

flatMap()主要是提取Optional中的屬性B的Optional<C>屬性中的C的值,而後再包裝到新的Optional

輸入Optional<B>,輸出Optional<C>

flatMap

public class FlatMapDemo {
    private static final String DEFAULT_NAME = "javalover";

    public static void main(String[] args) {
        getName(null);
    }

    // 取出 b.c.name
    public static void getName(B b){
        C c = Optional
                .ofNullable(b)
                // 這裏扁平化處理,提取Optional<C>中的C
                // 若是用map,則返回的是Optional<Optional<C>>
                .flatMap(b->b.getC())
                .orElse(new C("xxx"));
        System.out.println(c.getName());
    }
}

class B{
    private Optional<C> c;

    public Optional<C> getC() {
        return c;
    }

    public void setC(C c) {
        this.c = Optional.ofNullable(c);
    }
}

class C{
    private String name;

    public C(String name) {
        this.name = name;
    }
    // 省略getter/setter
}

4. 應用

從規範角度來說,是爲了代碼清晰,一看用Optional<T>變量,就知道T可能爲null;

從編碼角度來說,主要是應用在非空判斷;可是實際場景的話,有兩個

  1. 沒有用Optional進行包裹的參數:好比上面講到的例子,傳來的參數就是普通對象,咱們就須要本身用Optional容器來包裹傳來的參數,而後進行後續操做
// 取出c.name
public static void getName(C c){
    // 本身手動包裝 Optional<C>
    String nameNew = Optional
        .ofNullable(c)
        .map(c1->c1.getName())
        .orElse(DEFAULT_NAME);

    System.out.println("new: "+nameNew);
}
  1. 有用Optional進行包裹的參數:好比數據庫查詢時,咱們能夠用Optional來包裹查詢的結果並返回,這樣咱們分析結果的時候,只須要經過orElse()來獲取,同時還能夠設定默認值
// 返回Optional<Car>,經過.orElse(defaultCar)就能夠獲取返回值,若是返回值爲null,還能夠設定一個默認值defaultCar
Optional<Car> selectOne(SelectStatementProvider selectStatement);

總結

  1. Optional是什麼:一個容器,存放一個對象,對象能夠爲null
  2. 沒它 VS 有它:看場景

    • 若是隻是單個的if/else判斷,那就沒它會好點;
    • 若是嵌套比較多,或者原本傳來的數據就是Optional類型,那確定是Optional合適
  3. 核心操做:不經常使用的這裏就不寫了

    • 保存數據:工廠方法 of()ofNullable()
    • 處理數據:map(), filter(), flatMap()
    • 獲取數據:orElse()
  4. 應用:主要用在非空判斷,實際場景的話,咱們能夠用在數據庫查詢語句中

後記

最後,感謝你們的觀看,謝謝

原創不易,期待官人們的三連喲

相關文章
相關標籤/搜索