Optional類的方法
方法 | 描述 |
---|---|
empty | 返回一個空的Optional類實例 |
of | 將對象封裝到Optional類中去,要求對象不能夠為空,否則返回一個NullPointerException |
ofNullable | 獲取得到Optional類封裝的對象,如果對象為空,那么返回一個空實例,如果不為空,返回一個封裝了對象的Optional實例 |
filter | 如果值存在而且能夠滿足提供的謂詞,就返回包含該值的Optional對象,否則返回一個空的Optional類實例 |
map | 如果Optional類封裝的值存在,那么執行map函數中定義的內容 |
flatMap | 如果該值存在,通過Function函數,返回一個Optional類型的值,否則返回一個空的Optional類實例 |
get | 如果值存在,那么將Optional類實例封裝的值返回,否則將會拋出NoSuchElementException異常 |
isPresent | 如果存在封裝的對象,那么返回true;如果不存在,那么返回false |
ifPresent | 如果存在封裝的對象,那么執行后面的消費方法;如果不存在,那么不做任何事情 |
orElse | 如果Optional實例對象是empty,那么使用默認的值來代替 |
orElseGet | 如果有值,則獲取得到將其返回;如果沒有值,那么將會使用指定的函數生成的值 |
orElseThrow | 如果有值將其進行返回,否則拋出一個指定的異常 |
之前寫過一篇Optional類的說明,但是感覺不同情況下有不同的用法,所以現在結合源碼再將使用場景結合一下使用。
Optional類和泛型T是相互結合着的,表示的是Option這個箱子里面裝的是T類型的value,但是這個value有可能是null,也有可能不為null
/***
可能包含也可能不包含非空值的容器對象。
如果存在值,isPresent() 將返回 true,get() 將返回該值。
提供了依賴於包含值的存在與否的其他方法,例如 orElse()(如果值不存在則返回默認值)和 ifPresent()(如果值存在則執行代碼塊)。
這是一個基於值的類; 在 Optional 實例上使用身份敏感操作(包括引用相等 (==)、身份哈希碼或同步)可能會產生不可預測的結果,應該避免。
所以可以將這個類的實例理解成是一個對值做處理的容器
*/
public final class Optional<T> {
// Optiaonal箱子里面裝的值是T類型的為null的值
private static final Optional<?> EMPTY = new Optional<>();
// Optional這個箱子裝的值
private final T value;
// value為null
private Optional() {
this.value = null;
}
// 返回的是T類型的null。相當於是User user = null
// 只不過這里使用Optional類給包裝着
public static<T> Optional<T> empty() {
Optional<T> t = (Optional<T>) EMPTY;
return t;
}
// 如果傳遞過來的value是null,那么將會存在NPE
private Optional(T value) {
this.value = Objects.requireNonNull(value);
}
// 傳入進來的value如果是null,那么將會存在NPE
public static <T> Optional<T> of(T value) {
return new Optional<>(value);
}
// 如果value為null,那么返回Optional<null>;如果存在着值,那么返回Optional<value>
public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}
// 如果值為null,那么就直接拋出異常;如果不為null,就直接返回這個value。
// 這里說明了這里還是有可能存在着為null的可能性的
public T get() {
if (value == null) {
throw new NoSuchElementException("No value present");
}
return value;
}
// 如果value不是null,那么就直接返回true;如果value是null,那么就直接返回false;
public boolean isPresent() {
return value != null;
}
// 如果value不為null,那么就可以對這個value值來進行操作了
// 如果為null,那么就什么都不做
public void ifPresent(Consumer<? super T> consumer) {
if (value != null)
consumer.accept(value);
}
// 過濾方法。看看如何來進行實現的。
// 首先判斷predicate對象不能夠是空的,如果是空的就直接拋出空指針異常
// 然后在判斷這個是否有,可以看到,如果value為null,那么直接返回這個value為空的對象
// 如果value不為null的時候,然后進行下一步操作。如果value符合自定義的predicate,那么就直接返回這個value的實例對象;不然就返回的是value=null的實例 // 對象
public Optional<T> filter(Predicate<? super T> predicate) {
Objects.requireNonNull(predicate);
if (!isPresent())
return this;
else
return predicate.test(value) ? this : empty();
}
// 如果說這樣的對象不為null,那么就執行下面的步驟
// 如果當前對象的value為null,那么將會返回value為null的實例對象;如果不為null,那么就會按照mapper中的方法將值來進行轉換。
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));
}
}
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));
}
}
// 這個比較簡單了。自定義實現。如果value是空,那么就根據傳進來的值作為value
public T orElse(T other) {
return value != null ? value : other;
}
// 這個也是比較容易來理解的。如果value不為null,那么就直接返回;如果value為null,那么就自己來定義一個值賦值給value
public T orElseGet(Supplier<? extends T> other) {
return value != null ? value : other.get();
}
// 這個也是比較常用的地方。對於參數值校驗常做的。
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
if (value != null) {
return value;
} else {
throw exceptionSupplier.get();
}
}
/**
* Indicates whether some other object is "equal to" this Optional. The
* other object is considered equal if:
* <ul>
* <li>it is also an {@code Optional} and;
* <li>both instances have no value present or;
* <li>the present values are "equal to" each other via {@code equals()}.
* </ul>
*
* @param obj an object to be tested for equality
* @return {code true} if the other object is "equal to" this object
* otherwise {@code false}
*/
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof Optional)) {
return false;
}
Optional<?> other = (Optional<?>) obj;
return Objects.equals(value, other.value);
}
/**
* Returns the hash code value of the present value, if any, or 0 (zero) if
* no value is present.
*
* @return hash code value of the present value or 0 if no value is present
*/
@Override
public int hashCode() {
return Objects.hashCode(value);
}
/**
* Returns a non-empty string representation of this Optional suitable for
* debugging. The exact presentation format is unspecified and may vary
* between implementations and versions.
*
* @implSpec If a value is present the result must include its string
* representation in the result. Empty and present Optionals must be
* unambiguously differentiable.
*
* @return the string representation of this instance
*/
@Override
public String toString() {
return value != null
? String.format("Optional[%s]", value)
: "Optional.empty";
}
}
對上面的方法做了一個總結:可以發現上面的方法總體來說都是:對值是否是null來做了處理,防止出現空指針異常。
如果是null的話,可以實現怎樣的操作;如果不是null的話,又可以做怎樣的操作;以及對值可能為null的處理方式
構造方法中可以看到構造都被私有化了,只有本類中的其他的非private修飾的才能夠來創建實例化對象。
對於空參構造來說,創造出來的對象的value屬性為null;對於有參構造來說,value值不為null;
所以總結來說,是創建出來的對象不為null,value值可能是null,也可以不是null;具體的得看是哪個方法來進行調用的。
對於這個Optional類來說,加載類的時候就已經有了一個默認的EMPTY對象,value是為null的。
然后再來一個比較常用的:
Optional<User> optional = userRepository.selectOne(entity);
// 如果optional不為null,那么返回ok;否則返回后面的錯誤碼。
return optional.map(ResponseResult::getOk).orElseGet(() -> ResponseResult.getError("賬號/密碼錯誤"));
還有一個對參數校驗的
String str = null;
Optional.ofNullable(str).orElseThrow(()-> new RuntimeException("str為空"));