Java 知識點整理 Optional 的使用

前言

開發相關知識點整理,內容來自個人我的網站筆記,和收集參考的資料,因爲是發在社區,整理了排版和可讀性,對於內容我儘可能作到是通過驗證的,以避免誤人子弟。固然本人能力有限,若有錯誤或疑問,歡迎一塊兒討論和指正(有些內容也是我參考別人的,若有侵權,請聯繫我,通常我會註明轉載和參考原文)前端

一、什麼是Optional?

一句話歸納: 它是一個容器,用來包裝對象,解決NullPointerException異常的java

二、如何建立Optional對象?或者說如何用Optional來包裝對象或null值?

  • static Optional empty() :用來建立一個空的Optionalweb

  • static Optional of(T value) :用來建立一個非空的Optional後端

  • static Optional ofNullable(T value) :用來建立一個多是空,也可能非空的Optionalapp

其實上面這三個方法,看一下源碼就很清晰了,好比of函數

// 方法
public static <T> Optional<T> of(T value) {
        return new Optional<>(value);
    }
// 構造器
private Optional(T value) {
        this.value = Objects.requireNonNull(value);
    }
// Objects對象的requireNonNull方法
public static <T> T requireNonNull(T obj) {
        if (obj == null)
            throw new NullPointerException();
        return obj;
    }
複製代碼

of方法建立Optional對象,並對傳入值作NullPointerException異常判斷,因此,當你傳遞一個null值的時候,就會觸發異常了工具

再看看empty方法網站

// 方法
public static<T> Optional<T> empty() {
        @SuppressWarnings("unchecked")
        Optional<T> t = (Optional<T>) EMPTY;
        return t;
    }
// 靜態常量
private static final Optional<?> EMPTY = new Optional<>();

// 常量
private final T value;

// 構造器
private Optional() {
    this.value = null;
    }
複製代碼

一開始就定義了一個Optional<?> EMPTY的對象,而且構造函數使用默認的,value爲空。empty只是作了泛型的轉換ui

剩下的ofNullable就更簡單了,經過傳遞的值決定使用of仍是emptythis

public static <T> Optional<T> ofNullable(T value) {
        return value == null ? empty() : of(value);
    }
複製代碼

Optional類的源碼仍是比較簡單的,代碼不多,經過成員變量和構造方法的解讀,相信你已經理解了of,empty,ofNullable

三、如何使用Optional類?

最正確的作法就是對須要作NullPointerException異常判斷的對象,把它包裝成Optional類,而後指明對象不存在的時候,應該怎麼作,下面來看一下幾種常見的用法

1. orElse

public class OptionalTest {
    public static void main(String[] args) {
        HashMap<Integer, User> userHashMap = new HashMap<>();
        userHashMap.put(1, new User(1, "Xiao Ming"));
        userHashMap.put(2, new User(2, "Xiao Zhi"));
        userHashMap.put(3, null);

        UserUtil userUtil = new UserUtil(userHashMap); // 這個工具類只是爲了填充數據的,不要在乎這些細節,getUserByUserId方法能返回User對象

        // 包裝了User對象,而且使用orElse指明瞭對象不存在的時候應該返回指定的值,也就是new User(1, "Xiao Bai")
        User user = Optional
                .ofNullable(UserUtil.getUserByUserId(2))
                .orElse(new User(1, "Xiao Bai"));

    }
}

// 工具類,隨便寫的,經過hashMap模擬查詢用戶
public class User {
    public Integer id;
    public String name;

    public User(Integer id, String name) {
        this.id = id;
        this.name = name;
    }
}

class UserUtil {

    public static HashMap<Integer, User> hashMap;

    UserUtil(HashMap<Integer, User> hashMap) {
        UserUtil.hashMap = hashMap;
    }

    public static User getUserByUserId(Integer id) {
        User user = hashMap.get(id);
        System.out.println(user);
        return user;
    }
}
複製代碼

2. orElseGet

和 orElse 不一樣,它的參數接受一個lambda表達式

User user = Optional
                .ofNullable(UserUtil.getUserByUserId(2))
                .orElseGet(() -> new User(1, "Xiao Bai"));
複製代碼

3. orElseThrow

同理,傳遞一個lambda表達式異常(注意啊,方法是限定了參數的,觸發異常就用orElseThrow,不能用orElseGet)

User user = Optional
                .ofNullable(UserUtil.getUserByUserId(2))
                .orElseThrow(()-> new AssertionError("AssertionError"));
複製代碼

4. map

調用map後,若是當前 Optional 爲 Optional.empty,則依舊返回 Optional.empty;不然返回一個新的 Optional,該 Optional 包含的是:函數 mapper 在以 value 做爲輸入時的輸出值

好比下面的例子,第一次調用map後,獲取的是name,傳遞給下一個map的值至關於Optional.ofNullable(name)

String user = Optional.ofNullable(UserUtil.getUserByUserId(1))
                .map(user1 -> user1.name)
                .map(String::toLowerCase)
                .orElse("123");
        System.out.println(user);

// 方法
public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
        Objects.requireNonNull(mapper);
        if (!isPresent())
            return empty();
        else {
            return Optional.ofNullable(mapper.apply(value));
        }
    }
複製代碼

這個操做能夠用在對對象作屢次操做的場景下,而且保證爲空的時候返回指定的值,好比先獲取用戶的名稱,再獲取用戶的電話,作一下判斷後,再經過電話查詢到其它的數據,而後繼續...,最後若是某一環節出現異常,那就返回orElse定義的對象

5. flatMap

flatMap 方法與 map 方法的區別在於,map 方法參數中的函數 mapper 輸出的是值,而後 map 方法會使用 Optional.ofNullable 將其包裝爲 Optional;而 flatMap 要求參數中的函數 mapper 輸出的就是 Optional

.flatMap(user -> Optional.of(user.name()))

6. filter

都是差很少的套路,此次咱們先看源碼,能夠發現一樣是接受lambda表達式,而且要是一個Boolean返回值的,若是本次操做的optional是empty的,就返回自己

public Optional<T> filter(Predicate<? super T> predicate) {
        Objects.requireNonNull(predicate);
        if (!isPresent())
            return this;
        else
            return predicate.test(value) ? this : empty();
    }

// 函數式接口部分代碼,能夠看到test是要求返回Boolean類型的

@FunctionalInterface
public interface Predicate<T> {

    /** * Evaluates this predicate on the given argument. * * @param t the input argument * @return {@code true} if the input argument matches the predicate, * otherwise {@code false} */
    boolean test(T t);
}

// 例子
String name = Optional.ofNullable(UserUtil.getUserByUserId(1))
                .filter(user -> user.id == 2)
                .map(user -> user.name)
                .orElse("abc");
        System.out.println(name);
複製代碼

經過觀察源碼,咱們能夠看到,不少爲空的都會返回empty,這讓各個操做都可以互相調用

總結

Optional是一個比較簡單的類,推薦直接閱讀源碼,經過簡單的包裝,很優雅的解決的空指針問題,之前谷歌Guava庫就實現了,後面Java8正式把規範加到 java.util.Optional 類中。

另外,上面的作法是對於程序內的,若是是web開發,參數校驗,請使用Hibernate-Validator便可,做爲一個合格的後端,我不會讓前端挑刺的😀

相關文章
相關標籤/搜索