為什么說(shuō)JDK 8 Optional<T>
的實(shí)現(xiàn)挺不合理的?因?yàn)?code>Optional<T>值容器對(duì)“包含的值是否存在”是基于value != null
或value == null
判斷的末盔,而非基于isPresent()
方法筑舅。這樣實(shí)現(xiàn)的后果是很難做自定義擴(kuò)展,如果要做擴(kuò)展需要重新實(shí)現(xiàn)大部分接口陨舱。其基本數(shù)據(jù)類型的實(shí)現(xiàn)類OptionalInt
翠拣,也是基于isPresent
字段做判斷條件,藍(lán)瘦香菇游盲。maybe他們就不想讓我們做擴(kuò)展误墓,不然真想不出什么理由。public final class Optional<T>
益缎,final類??????谜慌。
擴(kuò)展性設(shè)計(jì)貫穿在集合框架的抽象類實(shí)現(xiàn)中,核心集合接口的基礎(chǔ)實(shí)現(xiàn)是全部基于抽象方法實(shí)現(xiàn)的莺奔。例如欣范,AbstractCollection<E>
、AbstractList<E>
令哟。
為什么會(huì)聊這個(gè)話題恼琼?因?yàn)槲覀冊(cè)趯?shí)際編程中都會(huì)通過(guò)HTTP請(qǐng)求調(diào)用他人的API,其成功/失敗的返回一般都是基于返回碼(code)來(lái)判斷的励饵,這時(shí)想基于Optional<T>
做擴(kuò)展驳癌,發(fā)現(xiàn)幾乎要重新實(shí)現(xiàn)所有方法,很杯具??役听。
下面是在JDK原有實(shí)現(xiàn)上颓鲜,基于擴(kuò)展性考慮修改的代碼。如有哪里不合理的地方甜滨,感謝指出來(lái)。
// [函數(shù)式接口] 可能包含null值的容器對(duì)象
public final class Optional<T> {
/**
* Common instance for {@code empty()}.
* 空實(shí)例({@linkplain #empty()})
*/
private static final Optional<?> EMPTY = new Optional<>();
/**
* If non-null, the value; if null, indicates no value is present
* null表示值不存在
*/
private final T value;
/**
* Constructs an empty instance.
*
* @implNote Generally only one empty instance, {@link Optional#EMPTY},
* should exist per VM.
*/
private Optional() {
this.value = null;
}
/**
* Returns an empty {@code Optional} instance. No value is present for this
* Optional.
*
* @apiNote Though it may be tempting to do so, avoid testing if an object
* is empty by comparing with {@code ==} against instances returned by
* {@code Option.empty()}. There is no guarantee that it is a singleton.
* Instead, use {@link #isPresent()}.
*
* @param <T> Type of the non-existent value
* @return an empty {@code Optional}
*/
// 核心方法 返回空實(shí)例
public static<T> Optional<T> empty() {
@SuppressWarnings("unchecked")
Optional<T> t = (Optional<T>) EMPTY;
return t;
}
/**
* Constructs an instance with the value present.
*
* @param value the non-null value to be present 存在的非null值
* @throws NullPointerException if value is null
*/
private Optional(T value) {
this.value = Objects.requireNonNull(value); // 必須是非null值
}
/**
* Returns an {@code Optional} with the specified present non-null value.
*
* @param <T> the class of the value 值的類型
* @param value the value to be present, which must be non-null 存在的值瘤袖,必須不是非null
* @return an {@code Optional} with the value present
* @throws NullPointerException if value is null 如果值是null艾扮,則拋出NPE
*/
// 核心方法 返回一個(gè)指定存在的非空值的可選實(shí)例
public static <T> Optional<T> of(T value) {
return new Optional<>(value);
}
/**
* Returns an {@code Optional} describing the specified value, if non-null,
* otherwise returns an empty {@code Optional}.
*
* @param <T> the class of the value 值的類型
* @param value the possibly-null value to describe 描述可為null的值
* @return an {@code Optional} with a present value if the specified value
* is non-null, otherwise an empty {@code Optional}
*/
// 核心方法 如果值非空占婉,返回一個(gè)描述指定值的可選實(shí)例泡嘴;否則,返回一個(gè)空實(shí)例
public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}
/**
* If a value is present in this {@code Optional}, returns the value,
* otherwise throws {@code NoSuchElementException}.
*
* @return the non-null value held by this {@code Optional}
* @throws NoSuchElementException if there is no value present
*
* @see Optional#isPresent()
*/
// 核心方法 如果值存在逆济,則返回該值酌予;否則磺箕,拋出沒(méi)有這個(gè)元素異常
public T get() {
// if (value == null) {
if (!isPresent()) {
throw new NoSuchElementException("No value present");
}
return value;
}
/**
* Return {@code true} if there is a value present, otherwise {@code false}.
*
* @return {@code true} if there is a value present, otherwise {@code false}
*/
// 核心方法 如果是存在的值,則返回true抛虫;否則松靡,返回false
public boolean isPresent() {
return value != null;
}
// 函數(shù)式接口
/**
* If a value is present, invoke the specified consumer with the value,
* otherwise do nothing.
*
* @param consumer block to be executed if a value is present
* @throws NullPointerException if value is present and {@code consumer} is
* null
*/
// 核心方法 如果值是存在的,則調(diào)用指定的操作消費(fèi)該值建椰;否則雕欺,什么都不做
public void ifPresent(Consumer<? super T> consumer) {
// if (value != null)
if (isPresent()) {
consumer.accept(value);
}
}
// 第一層:過(guò)濾
/**
* If a value is present, and the value matches the given predicate,
* return an {@code Optional} describing the value, otherwise return an
* empty {@code Optional}.
*
* @param predicate a predicate to apply to the value, if present
* @return an {@code Optional} describing the value of this {@code Optional}
* if a value is present and the value matches the given predicate,
* otherwise an empty {@code Optional}
* @throws NullPointerException if the predicate is null
*/
// 核心方法 如果值是存在的,并且值匹配給定的謂詞棉姐,則返回描述該值的可選實(shí)例阅茶;否則,返回空實(shí)例
public Optional<T> filter(Predicate<? super T> predicate) {
Objects.requireNonNull(predicate);
if (!isPresent()) {
return this;
} else {
return predicate.test(value) ? this : empty();
}
}
// 使用規(guī)則:flatMap(mapper) { map(mapper) }
/**
* If a value is present, apply the provided mapping function to it,
* and if the result is non-null, return an {@code Optional} describing the
* result. Otherwise return an empty {@code Optional}.
*
* @apiNote This method supports post-processing on optional values, without
* the need to explicitly check for a return status. For example, the
* following code traverses a stream of file names, selects one that has
* not yet been processed, and then opens that file, returning an
* {@code Optional<FileInputStream>}:
* <p>
* 本方法支持可選值的后置處理谅海,不需要顯示地檢查返回狀態(tài)脸哀。
* 例如,下面的代碼遍歷文件名稱列表的流扭吁,選擇一個(gè)尚未被處理的撞蜂,然后打開(kāi)該文件,并返回文件輸出流的可選實(shí)例:
*
* <pre>{@code
* Optional<FileInputStream> fis =
* names.stream().filter(name -> !isProcessedYet(name))
* .findFirst()
* .map(name -> new FileInputStream(name));
* }</pre>
*
* Here, {@code findFirst} returns an {@code Optional<String>}, and then
* {@code map} returns an {@code Optional<FileInputStream>} for the desired
* file if one exists.
* <p>
* {@code findFirst}返回一個(gè)字符串的可選實(shí)例侥袜,然后通過(guò)映射函數(shù)為存在的所需文件返回一個(gè)文件輸入流的可選實(shí)例蝌诡。
*
* @param <U> The type of the result of the mapping function 映射函數(shù)的結(jié)果類型
* @param mapper a mapping function to apply to the value, if present 如果值存在,應(yīng)用到值的映射函數(shù)
* @return an {@code Optional} describing the result of applying a mapping
* function to the value of this {@code Optional}, if a value is present,
* otherwise an empty {@code Optional} 返回一個(gè)描述應(yīng)用映射函數(shù)到該可選實(shí)例值的結(jié)果的可選實(shí)例
* @throws NullPointerException if the mapping function is null
*/
// 核心方法 如果值是存在的枫吧,則應(yīng)用給定的映射函數(shù)浦旱,并且結(jié)果是非空的,則返回描述該結(jié)果的可選實(shí)例九杂;否則颁湖,返回空實(shí)例
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)); // 映射結(jié)果可能為null,包裝成Optional
}
}
/**
* If a value is present, apply the provided {@code Optional}-bearing
* mapping function to it, return that result, otherwise return an empty
* {@code Optional}. This method is similar to {@link #map(Function)},
* but the provided mapper is one whose result is already an {@code Optional},
* and if invoked, {@code flatMap} does not wrap it with an additional
* {@code Optional}.
* <p>
* 本方法和{@link #map(Function)}相似例隆,但提供的映射函數(shù)的結(jié)果已是一個(gè)可選實(shí)例甥捺,
* 如果被調(diào)用,本方法并不會(huì)使用一個(gè)額外的可選實(shí)例包裝它镀层。
*
* @param <U> The type parameter to the {@code Optional} returned by 返回的可選實(shí)例的類型參數(shù)
* @param mapper a mapping function to apply to the value, if present
* the mapping function 應(yīng)用到值的映射函數(shù)
* @return the result of applying an {@code Optional}-bearing mapping
* function to the value of this {@code Optional}, if a value is present,
* otherwise an empty {@code Optional}
* @throws NullPointerException if the mapping function is null or returns
* a null result
*/
// 核心方法 如果值是可選的镰禾,則應(yīng)用提供的可選關(guān)系映射函數(shù),然后返回該結(jié)果唱逢;否則吴侦,返回空實(shí)例
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)); // Optional<U>不能為null,原生返回
}
}
/**
* Return the value if present, otherwise return {@code other}.
*
* @param other the value to be returned if there is no value present, may
* be null 可能為null
* @return the value, if present, otherwise {@code other}
*/
// 核心方法 如果值存在坞古,則返回該值备韧;否則,返回默認(rèn)值
public T orElse(T other) {
// return value != null ? value : other;
return isPresent() ? value : other;
}
/**
* Return the value if present, otherwise invoke {@code other} and return
* the result of that invocation.
*
* @param other a {@code Supplier} whose result is returned if no value
* is present
* @return the value if present otherwise the result of {@code other.get()}
* @throws NullPointerException if value is not present and {@code other} is
* null
*/
// 核心方法 如果值存在绸贡,則返回該值盯蝴;否則,調(diào)用結(jié)果提供者并返回調(diào)用的結(jié)果
// 使用場(chǎng)景:數(shù)據(jù)多層保護(hù)設(shè)計(jì)听怕,如Cache + DB
public T orElseGet(Supplier<? extends T> other) {
// return value != null ? value : other.get();
return isPresent() ? value : other.get();
}
/**
* Return the contained value, if present, otherwise throw an exception
* to be created by the provided supplier.
*
* @apiNote A method reference to the exception constructor with an empty
* argument list can be used as the supplier. For example,
* {@code IllegalStateException::new}.
* <p>
* 一個(gè)引用使用空參數(shù)列表異常構(gòu)造器的方法捧挺,可用于異常供應(yīng)商。
* 例如尿瞭,{@code IllegalStateException::new}闽烙。
*
* @param <X> type of the exception to be thrown 待拋出的異常類型
* @param exceptionSupplier The supplier which will return the exception to
* be thrown 返回異常的供應(yīng)商
* @return the present value
* @throws X if there is no value present
* @throws NullPointerException if no value is present and
* {@code exceptionSupplier} is null
*/
// 核心方法 如果值存在,則返回包含的值声搁;否則黑竞,拋出一個(gè)由提供的供應(yīng)商創(chuàng)建的異常
// 使用場(chǎng)景:基于異常的快速失敗設(shè)計(jì)(fail-fast)
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
// if (value != null) {
if (isPresent()) {
return value;
} else {
throw exceptionSupplier.get(); // 值為null,則拋出異常
}
}
// ----------------- Object -----------------
/**
* 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) {
// 《Effective Java》總結(jié)的優(yōu)化實(shí)現(xiàn)
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
return isPresent()
? String.format("Optional[%s]", value)
: "Optional.empty"; // 空實(shí)例
}
}
祝玩得開(kāi)心疏旨!ˇ?ˇ
云舒很魂,2017.7.23,杭州