簡體   English   中英

空字符串的 Optional 實現

[英]An implementation of Optional for empty Strings

關於 Optional 的最好的事情之一是它將所有樣板檢查null值保存在一個長鏈中:

Optional.ofNullable(myService.getSomething())
    .map(secondService::fetch)
    .map(thirdService::fetchAgain)
    // And so forth...

如果map返回null則 Optional 將在任何時候跳到“空”軌道map

如果可以為字符串做類似的事情而不是每次都檢查它們的String::isEmpty那就太好了:

Optional.ofNullable(entity.getName())
    .filter(String::isEmpty)
    .map(Utils::performSomeOperation)
    .filter(String::isEmpty)
    .or(service::getMostCommonName)
    .filter(String::isEmpty)
    .orElse("Bob");

像這樣的東西:

OptionalString.ofEmptyable(entity.getName())
    .map(Utils::performSomeOperation)
    .or(service::getMostCommonName)
    .orElse("Bob");

Optional 中的關鍵邏輯發生在ofNullable當它調用對value == null檢查時。 從理論上講,您可以在其中應用任何類型的邏輯:

MagicalOptionalString(StringUtils::isNotBlank).ofEmptyable(entity.getName())
    .map(Utils::performSomeOperation)
    .or(service::getMostCommonName)
    .orElse("Bob");

但是,Optional 是最終的,阻止了擴展此行為的任何直接方式。 那么是否已經有一個現有的、健壯的實現呢?

嘗試一些事情來解決您的目標,並意識到我會贊同 VGR 的想法,因為與使用現有方法相比,實現這樣的用例需要做很多額外的工作。

然而,在花了一些時間查看實現后,我可以添加的細節很少 -

作為實用程序,您可以實現一個靜態實現,該實現驗證字符串輸入的nullisEmpty條件並相應地返回Optional 代碼可能看起來像 -

private static Optional<String> ofEmptyable(String string) {
    return isNullOrEmpty(string) ? Optional.empty() : Optional.of(string);
}

private static boolean isNullOrEmpty(String target) {
    return target == null || target.isEmpty();
}

這可以取代ofNullable的使用,它專門檢查null (Optional 的主要目的)。


由於您的問題陳述中的期望是實際處理每個方法( map / or / orElse )調用的情況,如可選,一種類似於OptionalInt可能是將自定義OptionalString實現為 -

public final class OptionalString {

    private static final OptionalString EMPTY = new OptionalString();

    private final boolean isPresent;
    private final String value;

    private OptionalString() {
        this.isPresent = false;
        this.value = "";
    }

    private static OptionalString empty() {
        return EMPTY;
    }

    private boolean isPresent() {
        return isPresent;
    }

    private OptionalString(String value) {
        this.isPresent = true;
        this.value = value;
    }

    public static OptionalString of(String value) {
        return value == null || value.isEmpty() ? OptionalString.empty() : new OptionalString(value);
    }

    public OptionalString map(Function<? super String, ? extends String> mapper) {
        return !isPresent() ? OptionalString.empty() : OptionalString.of(mapper.apply(this.value));
    }

    public OptionalString or(Supplier<String> supplier) {
        return isPresent() ? this : OptionalString.of(supplier.get());
    }

    String orElse(String other) {
        return isPresent ? value : other;
    }

    public String getAsString() {
        return Optional.of(value).orElseThrow(() -> new NoSuchElementException("No value present"));
    }
}

可以通過以下方式為您的用例進一步實施 -

String customImpl = OptionalString.of(entity.getName())
            .map(OptionalStringTest::trimWhiteSpaces) // OptionalStringTest is my test class name where 'trimWhiteSpaces' operation on String resides
            .or(service::getMostCommonName)
            .orElse("learning");
System.out.println(String.format("custom implementation - %s", customImpl));

在哪里

private static String trimWhiteSpaces(String x) {
    return x.trim();
}

注意- 老實說,我找不到在 JDK 中預先沒有OptionalString類的基本原理(我之所以這么說是因為我懷疑它背后肯定有一個想法),我相信它只是我的范圍半徑要小得多,我希望有人可以在這里添加細節。 恕我直言,使用Optional<String>似乎幾乎所有你想要的東西都在那里,這讓我們回到了循環的開始。

對於任何在 Kotlin 工作的人來說,這真的很容易做到:

class NonEmptyString private constructor(val Email: String) {
    companion object Factory {
        operator fun invoke(value: String?): T? = value?.let { if (it.isNotEmpty()) NonEmptyString(value) else null }
    }
}

“靜態” invoke函數根據它是否有效有條件地創建一個新對象。 並允許您像構造函數一樣調用它( NonEmptyString(value) )。 私有構造函數強制您使用invoke方法。

因為如果它無效,它會返回一個 null,並且 Kotlin 內置了 null 安全,所以它可以很容易鏈接。 添加mapflatMap函數非常簡單。

有關我編寫的更全面、更通用的示例,請參閱此 Code Review 問題

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM