Java8特性學習筆記(三) Optional

參考:

簡介

Optional 是 Java8 提供的為了解決 null 安全問題的一個 API。善用 Optional 可以使我們代碼中很多繁瑣的設計變得十分優(yōu)雅。

示例

為了方便,我們先定義一個簡單的實體類 Book。

public class Book {
    
    private String name;
    private float price;

    public Book(String name, float price) {
        this.name = name;
        this.price = price;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public float getPrice() {
        return price;
    }

    public void setPrice(float price) {
        this.price = price;
    }

    @Override
    public String toString() {
        return "Book{" +
                "name='" + name + '\'' +
                ", price=" + price +
                '}';
    }
}

然后看個例子,傳統(tǒng)寫法如下:

public static String getName(Book book) {
    if (book == null || book.getName() == null)
        return "Unknown";
    return book.getName();
}

使用 Optional 改為鏈式調用如下:

public static String getName(Book book) {
    return Optional.ofNullable(book)
            .map(user->user.getName())
            .orElse("Unknown");
}

不推薦的寫法如下,這其實只是用 isPresent 方法來替代 u==null。

public static String getName(Book book) {
    Optional<Book> myBook = Optional.ofNullable(book);
    if (!myBook.isPresent())
        return "Unknown";
    return myBook.get().getName();
}

構造方法

Java 提供三個靜態(tài)方法來構造一個Optional:

  • Optional.of(T value),該方法通過一個非 null 的 value 來構造一個 Optional,返回的 Optional 包含了 value 這個值。對于該方法,傳入的參數一定不能為 null,否則便會拋出 NullPointerException。
Optional<String> optStr1 = Optional.of("optional");
  • Optional.ofNullable(T value),該方法和 of 方法的區(qū)別在于,傳入的參數可以為 null , 但是前面 javadoc 不是說 Optional 只能包含非 null 值嗎?原來該方法會判斷傳入的參數是否為 null,如果為 null 的話,返回的就是 Optional.empty()。
Optional<String> optStr2 = Optional.ofNullable(null);
  • Optional.empty(),該方法用來構造一個空的 Optional,即該 Optional 中不包含值,其實底層實現(xiàn)還是 如果 Optional 中的 value 為 null 則該 Optional 為不包含值的狀態(tài),然后在 API 層面將 Optional 表現(xiàn)的不能包含 null 值,使得 Optional 只存在 包含值 和 不包含值 兩種狀態(tài)。
Optional<String> optStr = Optional.empty();

API方法

介紹一些經常使用的方法。

get

get()方法主要用于返回包裝對象的實際值,但是如果包裝對象值為null,會拋出NoSuchElementException異常。

示例:

String name = Optional.ofNullable(book).get().getName(); // book 不能為空

方法源碼:

public T get() {
    if (value == null) {
        throw new NoSuchElementException("No value present");
    }
    return value;
}

isPresent

isPresent()方法用于判斷包裝對象的值是否非空。

使用示例:

System.out.println(Optional.ofNullable(book).isPresent()); 

方法源碼:

public boolean isPresent() {
    return value != null;
}

ifPresent

ifPresent()方法接受一個Consumer對象(消費函數),如果包裝對象的值非空,運行Consumer對象的accept()方法。

示例:

public static void printName(Book book) {
    Optional.ofNullable(book).ifPresent(b ->  System.out.println("The Book name is : " + b.getName()));
}

方法源碼:

public void ifPresent(Consumer<? super T> consumer) {
    if (value != null)
        consumer.accept(value);
}

filter

filter() 方法接受參數為 Predicate 對象,用于對 Optional 對象進行過濾,如果符合 Predicate 的條件,返回 Optional 對象本身,否則返回一個空的 Optional 對象。舉例如下:

示例:

public static void filterPrice(Book book) {
    Optional.ofNullable(book).filter( b -> b.getPrice() > 10.0).ifPresent(b ->  System.out.println("The book price is more than 10.0."));
}

方法源碼:

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

map

map() 方法的參數為 Function(函數式接口)對象,map()方法將 Optional 中的包裝對象用 Function 函數進行運算,并包裝成新的 Optional 對象(包裝對象的類型可能改變)。

public static Optional<Float> getPrice(Book book) {
    return Optional.ofNullable(book).map(u -> u.getPrice());
}

方法源碼:

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));
    }
}

flatMap

跟map()方法不同的是,入參Function函數的返回值類型為 Optional<U> 類型,而不是 U 類型,這樣 flatMap() 能將一個二維的Optional對象映射成一個一維的對象。將上例進行faltMap()改寫如下:

public static Optional<Float> getPrice(Book book) {
    return Optional.ofNullable(book).flatMap(b -> Optional.ofNullable(b.getPrice()));
}

方法源碼:

public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) {
    Objects.requireNonNull(mapper);
    if (!isPresent())
        return empty();
    else {
        return Objects.requireNonNull(mapper.apply(value));
    }
}

orElse

orElse()方法功能比較簡單,即如果包裝對象值非空,返回包裝對象值,否則返回入參other的值(默認值)。

示例:

public static String getName(Book book) {
    return Optional.ofNullable(book)
            .map(user->user.getName())
            .orElse("Unknown");
}

方法源碼:

public T orElse(T other) {
    return value != null ? value : other;
}

orElseGet

orElseGet()方法與orElse()方法類似,區(qū)別在于orElseGet()方法的入參為一個Supplier對象,用Supplier對象的get()方法的返回值作為默認值。

示例:

public static String getName(Book book) {
    return Optional.ofNullable(book)
            .map(user->user.getName())
            .orElseGet(() -> "Unkown");
}

方法源碼:

public T orElseGet(Supplier<? extends T> other) {
    return value != null ? value : other.get();
}

orElseThrow

orElseThrow()方法其實與orElseGet()方法非常相似了,入參都是Supplier對象,只不過orElseThrow()的Supplier對象必須返回一個Throwable異常,并在orElseThrow()中將異常拋出。

示例:

public static String getName(Book book) {
    return Optional.ofNullable(book)
            .map(user->user.getName())
            .orElseThrow(() -> new RuntimeException("Unkown"));
}

方法源碼:

public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
    if (value != null) {
        return value;
    } else {
        throw exceptionSupplier.get();
    }
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容