App下載

Java 的 Optional 并不能補(bǔ)充所有傳統(tǒng)的 if-null-else 或 if-not-null-else 檢查

養(yǎng)了一個(gè)閑月亮 2021-10-08 10:19:18 瀏覽數(shù) (2479)
反饋

Java 添加的?java.util.Optional?非常的受歡迎,并為總是不能返回非null值的方法提供了更流暢的代碼。很不幸的是,?Optional?已被濫用,一種濫用,甚至已被過(guò)度使用。當(dāng)與直接使用相比?null?沒(méi)有明顯優(yōu)勢(shì)時(shí),我偶爾會(huì)遇到使用?Optional的代碼。

當(dāng) Optional 與直接檢查 null 相比沒(méi)有任何優(yōu)勢(shì),調(diào)用代碼對(duì)它剛剛調(diào)用的方法的返回值使用?Optional.ofNullable(T)?時(shí),可能會(huì)提示一個(gè)危險(xiǎn)信號(hào)。如同所有的“危險(xiǎn)信號(hào)”,這并不意味著將方法將返回值傳遞個(gè)?Optional.ofNullable(T)?(事實(shí)上,傳遞給期望 Optional 的 API 是必要的),但它的這種做法通常是用于不提供實(shí)際值,而不是直接使用返回值并檢查它的是否為 null。

在 Optional 可用之前,用于檢查 null 方法返回的代碼以及對(duì) null 響應(yīng)采取一種方式和對(duì)非 null 響應(yīng)采取另一種方式的代碼如下所示)。

/**
 * Demonstrates approach to conditional based on {@code null} or
 * not {@code null} that is traditional pre-{@link Optional} approach.
 */
public void demonstrateWithoutOptional()
{
    final Object returnObject = methodPotentiallyReturningNull();
    if (returnObject == null)
    {
        out.println("The returned Object is null.");
    }
    else
    {
        out.println("The returned object is NOT null: " + returnObject);
        // code processing non-null return object goes here ...
    }
}

對(duì)于這個(gè)基本條件,很少需要涉及Optional。下一個(gè)代碼片段代表了我在開(kāi)發(fā)人員嘗試使用Optional替換顯式空檢測(cè)時(shí)偶爾看到的代碼類(lèi)型:

/**
 * Demonstrates using {@link Optional} in exactly the manner {@code null}
 * is often used (conditional on whether the returned value is empty or
 * not versus on whether the returned value is {@code null} or not).
 */
public void demonstrateOptionalUsedLikeNullUsed()
{
    final Optional<Object> optionalReturn
       = Optional.ofNullable(methodPotentiallyReturningNull());
    if (optionalReturn.isEmpty())
    {
        out.println("The returned Object is empty.");
    }
    else
    {
        out.println("The returned Object is NOT empty: " + optionalReturn);
        // code processing non-null return object goes here ...
    }
}

此代碼中的范式與傳統(tǒng)的null檢查代碼基本相同,但使用?Optional.isEmpty()?執(zhí)行相同的檢查。這種方法不會(huì)增加任何可讀性或其他優(yōu)勢(shì),但確實(shí)以額外的對(duì)象實(shí)例化和方法調(diào)用為代價(jià)。

上述用法的一個(gè)變體Optional是將其?ifPresent(Consumer)?方法與其?isEmpty()?方法結(jié)合使用,形成相同的基本邏輯,如果返回值存在則做一件事,如果返回值為空則做另一件事。這在以下代碼中進(jìn)行了演示。

/**
 * Demonstrates using {@link Optional} methods {@link Optional#ifPresent(Consumer)}
 * and {@link Optional#isEmpty()} in similar manner to traditional condition based
 * on {@code null} or not {@code null}.
 */
public void demonstrateOptionalIfPresentAndIsEmpty()
{
    final Optional<Object> optionalReturn
       = Optional.ofNullable(methodPotentiallyReturningNull());
    optionalReturn.ifPresent(
       (it) -> out.println("The returned Object is NOT empty: " + it));
    if (optionalReturn.isEmpty())
    {
        out.println("The returned object is empty.");
    }
}

這段代碼看起來(lái)比直接檢查 的返回值的傳統(tǒng)方法要短一些null,但仍然以額外的對(duì)象實(shí)例化為代價(jià),并且需要兩次方法調(diào)用。此外,首先檢查 Optional 是否存在然后立即檢查它是否為空感覺(jué)有點(diǎn)奇怪。此外,如果需要執(zhí)行的邏輯比將消息寫(xiě)到標(biāo)準(zhǔn)輸出更復(fù)雜,這種方法就變得不那么實(shí)用了。

結(jié)論

代碼,處理一個(gè)方法的返回值,需要做一兩件事,如果返回值是null做另一件事,如果返回值是不是 null很少會(huì)享受到環(huán)繞的任何優(yōu)勢(shì),在返回的值Optional簡(jiǎn)單地檢查它是否是現(xiàn)在還是空的。將方法的返回值包裝在Optional中 可能只有Optional在流暢的鏈接或與Optional.


0 人點(diǎn)贊