1. 程式人生 > 實用技巧 >java8的Optional

java8的Optional

前言

  java中的null是每位java開發者無法迴避的問題,也是無比痛恨的問題。邏輯上明明正常的程式,在執行的時候卻偏偏會丟擲NullPointException。在做所有的操作之前(set/get/equals等),都必須加上一行"if(xxx != null)"來進行判斷,否則有很大概率會在執行時看到一堆NullPointException。另外有些工作經驗的程式設計師都知道,就算本人心裡很放心物件不會為null,也必須判斷,否則程式碼上線前的sonar檢查一般都是通不過的。

Optional的使用

​   java的建立者在後來也發現了這個問題,對於null,建立者們現在的普遍觀點也是認為這是一個失誤。所以在java8中對此做出了相應的補救措施,這個補救就是Optional類。

​   通過將物件(空物件/非空物件)放入Optional類中,然後通過Optional提供的API來獲取和操作該類,幫助優雅的對null進行相應的處理。而不是在程式碼中寫一大堆類似"if(xxx != null)"的程式碼。

​   我們應該將需要操作的物件先放入Optional物件中,再進行相應的操作,這就要求我們首先得構建出Optional物件。檢視Optional的原始碼可以發現,該類的所有構造方法均被private修飾,所以需要通過Optional類提供的一些靜態方法來構建。常用的靜態方法有如下三個:

Optional optional = Optional.of(object); //
如果object==null,會丟擲NullPointerException Optional optional = Optional.ofNullable(object); // 如果object==null,底層呼叫Optional.Empty()方法建立Optional物件 Optional optional = Optional.empty(); // 返回一個value==null的Optional物件

  通過上述三個方法中的任意一個,都可以得到一個Optional物件,其中常用的是前兩個。

​   對於Optional的物件,一般還有兩個常用的API,分別是:

boolean isNull = optional.isPresent(); //
判斷optional中的物件是否為非null物件 Object object = optional.get(); // 從optional中取出放置的物件。如果放置的值為null,那麼會丟擲NoSuchElementException異常

  下面開始舉一個實際的小案例來說明應該如何使用Optional。假設我們有一個student的物件,現在需要呼叫其getName()方法

Student student = ....; // 通過某種方式(new/db/method等)獲得,所以可能為null
// 不使用Optional的方式
if(student != null) { 
    student.getName(); 
}
// 使用Optional的方式
Optional<Student> optional = Optional.ofNullable(student); // 不能使用Optional.of(),因為不確實student是否為null
if(optional.isPresent()) {
    Student stu = optional.get(); // optional.isPresent()為true,說明其中存放的物件不會為null
    stu.getName();
}

  上述程式碼完美的實現了功能,避免的NullPotionException。但是明顯能看到,對於null的判斷反而複雜化了,而且從程式碼的閱讀角度來說,這樣的程式碼多了之後,明顯對程式碼的閱讀也會帶來不小的負擔。畢竟java中"get()"這樣的方法挺多的(像ThreadLocal等)。

​   所以Optional的使用的正確開啟方式明顯不是這樣的。對比java8中另一大特性Stream來看,我們會發現,java8中特別推崇的一種編碼風格就是流式程式設計。Optional不外如是。

​   下面我們嘗試通過流失程式設計的方式,美化下上述程式碼。

​   這裡引入一個新的API——isElse(object)。一般搭配Optional.ofNullable(object)使用。如果Optional.ofNullable(object)中的object==null,那麼就會走isElse作為保底,保證Optional物件中存放的物件一定不為null。所以就可以寫出如下程式碼:

// 流式程式設計。  orElse返回值是T(Optional<T>)
Optional.ofNullable(student).orElse(new Student()).getName();

  orElse系列方法其實有三個,一般都是配合Optional.ofNullable(object)使用,分別如下:

orElse(T other); // 保底,如果Optional.ofNullable(object)中的object==null,那就返回傳入的other
orElseGet(Supplier<? extends T> other); // 保底,如果如果Optional.ofNullable(object)中的object==null,返回傳入lambda表示式返回的值
orElseThrow(Supplier<? extends X> exceptionSupplier); // 保底,如果Optional.ofNullable(object)中的object==null,返回傳入lambda表示式丟擲的異常

  更多的時候,Optional配合Stream可以寫出非常簡潔的流式程式設計的程式碼,程式碼如下:

public class Test {
    
    public static void main(String[] args) {
        Student student = new Student();
        List<String> collect = Optional.ofNullable(student.getCourses())
                                       .orElse(new ArrayList<>())
                                       .stream().map(s -> s)
                                       .collect(Collectors.toList()); 
    }
    @Data
    static class Student {
        List<String> courses ;
    }
}