參考:
- http://www.itdecent.cn/p/d81a5f7c9c4e
- https://zhuanlan.zhihu.com/p/40966718
- https://blog.kaaass.net/archives/764
簡介
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();
}
}