簡體   English   中英

結合可選項的最優雅方式是什么?

[英]What's the most elegant way to combine optionals?

這是我到目前為止所得到的:

Optional<Foo> firstChoice = firstChoice();
Optional<Foo> secondChoice = secondChoice();
return Optional.ofNullable(firstChoice.orElse(secondChoice.orElse(null)));

這讓我覺得既可怕又浪費。 如果存在 firstChoice,我將不必要地計算 secondChoice。

還有一個更高效的版本:

Optional<Foo> firstChoice = firstChoice();
if(firstChoice.isPresent()) {
 return firstChoice;
} else {
 return secondChoice();
}

在這里,我不能在不復制映射器或聲明另一個局部變量的情況下將某些映射函數鏈接到最后。 所有這些使得代碼比要解決的實際問題更復雜。

我更願意寫這個:

return firstChoice().alternatively(secondChoice());

但是 Optional::alternatively 顯然不存在。 怎么辦?

嘗試這個:

firstChoice().map(Optional::of)
             .orElseGet(this::secondChoice);

map 方法給你一個Optional<Optional<Foo>> 然后, orElseGet方法將其orElseGet平為Optional<Foo> secondChoice方法僅在firstChoice()返回空的可選項時才會被評估。

您可以簡單地將其替換為,

Optional<Foo> firstChoice = firstChoice();
return firstChoice.isPresent()? firstChoice : secondChoice();

除非firstChoice.isPresent()為 false,否則上面的代碼不會調用。

但是您必須准備好調用這兩個函數以獲得所需的輸出。 沒有其他方法可以逃避檢查。

  • 最好的情況是返回 true 的首選。
  • 最壞的情況是 First choice 返回 false,因此另一個方法調用第二個選項。

也許是這樣的:

Optional<String> finalChoice = Optional.ofNullable(firstChoice()
    .orElseGet(() -> secondChoice()
    .orElseGet(() -> null)));

來自: Java 8 中的鏈式可選項

這是@marstran 解決方案對任意數量選項的概括:

@SafeVarargs
public static <T> Optional<T> selectOptional(Supplier<Optional<T>>... optionals) {
    return Arrays.stream(optionals)
            .reduce((s1, s2) -> () -> s1.get().map(Optional::of).orElseGet(s2))
            .orElse(Optional::empty).get();
}

測試:

public static Optional<String> first() {
    System.out.println("foo called");
    return Optional.empty();
}

public static Optional<String> second() {
    System.out.println("bar called");
    return Optional.of("bar");
}

public static Optional<String> third() {
    System.out.println("baz called");
    return Optional.of("baz");
}

public static void main(String[] args) {
    System.out.println(selectOptional(() -> first(), () -> second(), () -> third()));
}

輸出:

foo called
bar called
Optional[bar]

Java 8 不支持這一點,這讓我感到非常沮喪,於是我又切換回了具有or guava 選項:

public abstract Optional<T> or(Optional<? extends T> secondChoice)

如果存在值,則返回此 Optional ; secondChoice 否則。

惰性計算和任意數量的Optional元素

Stream.<Supplier<Optional<Foo>>>of(
        this::firstChoice,
        this::secondChoice
).map(
        Supplier::get
).filter(
        Optional::isPresent
).findFirst(
).orElseGet(
    Optional::empty
);

Java 9 添加了Optional.or​(Supplier<? extends Optional<? extends T>> supplier)方法,專為這種情況而設計:

Optional<Foo> firstChoice = firstChoice();
return firstChoice.or(this::secondChoice);

這具有僅在firstChoice為空時計算secondChoice的額外好處。

這是一種適用於基於流 API 的任意數量的Optional的方法:

return Arrays.asList(firstChoice, secondChoice).stream()
  .filter(Optional::isPresent)
  .map(Optional::get)
  .findFirst().orElse(null);

這不是最短的。 但更通俗易懂。

如果您已經在使用其中一個庫,另一種方法是使用來自 commons-lang 的 Guava 的firstNonNull()

firstNonNull(firstChoice.orElse(null), secondChoice.orElse(null));

暫無
暫無

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

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