web-dev-qa-db-ja.com

オプションを組み合わせる最もエレガントな方法は何ですか?

ここに私がこれまでに得たものがあります:

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は存在しません。それで?

32

これを試して:

_firstChoice().map(Optional::of)
             .orElseGet(this::secondChoice);
_

Mapメソッドは_Optional<Optional<Foo>>_を提供します。次に、orElseGetメソッドはこれを_Optional<Foo>_にフラット化します。 secondChoiceメソッドは、firstChoice()が空のオプションを返す場合にのみ評価されます。

42
marstran

それを単に置き換えることができます、

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

firstChoice.isPresent()がfalseでない限り、上記のコードは呼び出されません。

ただし、目的の出力を取得するには、両方の関数を呼び出す準備をする必要があります。チェックを回避する方法は他にありません。

  • 最良の場合は、最初の選択がtrueを返すことです。
  • 最悪の場合は、最初の選択がfalseを返すため、別のメソッド呼び出しが2番目の選択になります。
5
Suresh Atta

任意の数のオプションに対する@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]
4
Tagir Valeev

たぶんこのようなもの:

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

From: Chaining Optionals in Java 8

4
Marthym

これがJava 8でサポートされていなかったという事実に十分イライラしていました。つまり、 or

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

値が存在する場合、このOptionalを返します。それ以外の場合はsecondChoice。

1
Erik

遅延計算と任意の数のOptional要素

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