JavaでオプションのorElse


Answers

現行のAPIを使用した場合、最もクリーンな「サービスを試してください」アプローチは次のようになります。

Optional<Result> o = Stream.<Supplier<Optional<Result>>>of(
    ()->serviceA(args), 
    ()->serviceB(args), 
    ()->serviceC(args), 
    ()->serviceD(args))
.map(Supplier::get)
.filter(Optional::isPresent)
.map(Optional::get)
.findFirst();

重要な点は、一度だけ記述しなければならない(定数の)連鎖ではなく、別のサービスを追加すること(またはサービスのリストを変更することは一般的です)がどれほど簡単かということです。 ここでは、単一の()->serviceX(args)追加または削除するだけで十分です。

ストリームの怠惰な評価のため、先行のサービスが空でないOptional返した場合、サービスは呼び出されません。

Question

私はJava 8の新しいOptional型を扱っています。機能的にはサポートされていない一般的な操作のように見えます: "orElseOptional"

次のパターンを考えてみましょう。

Optional<Result> resultFromServiceA = serviceA(args);
if (resultFromServiceA.isPresent) return result;
else {
    Optional<Result> resultFromServiceB = serviceB(args);
    if (resultFromServiceB.isPresent) return resultFromServiceB;
    else return serviceC(args);
}

このパターンには多くの形がありますが、オプションの "orElse"が必要な場合は、現在のものが存在しない場合にのみ呼び出される新しいオプションの関数を取ります。

実装は次のようになります。

public Optional<T> orElse(Supplier<Optional<? extends T>> otherSupplier) {
    return value != null ? this : other.get();
}

このような方法が存在しない理由があれば、私は不思議です。私が意図しない方法でOptionalを使用しているだけで、このケースに対処するために他の方法を思いついたのです。

カスタムユーティリティクラス/メソッドを含むソリューションは、自分のコードで作業している人が必ずしも存在しているとは知りませんので、エレガントではないと私は考えるべきです。

また、誰かが知っているなら、そのようなメソッドはJDK 9に含まれていますか?そのようなメソッドはどこで提案されますか? これは私にとってAPIへのかなりの目立たない漏れのようです。




おそらく、これはあなたが後にしていることです: 1つのオプションから別のものを得る

それ以外の場合は、 Optional.orElseGet参照してください。 私あなたが後にしていると思うものの例です:

result = Optional.ofNullable(serviceA().orElseGet(
                                 () -> serviceB().orElseGet(
                                     () -> serviceC().orElse(null))));



あなたがJDK8上にいると仮定すると、いくつかのオプションがあります。

オプション#1:独自のヘルパーメソッドを作成する

例えば:

public class Optionals {
    static <T> Optional<T> or(Supplier<Optional<T>>... optionals) {
        return Arrays.stream(optionals)
                .map(Supplier::get)
                .filter(Optional::isPresent)
                .findFirst()
                .orElseGet(Optional::empty);
    }
}

あなたがすることができるように:

return Optionals.or(
   ()-> serviceA(args),
   ()-> serviceB(args),
   ()-> serviceC(args),
   ()-> serviceD(args)
);

オプション#2:ライブラリを使用する

例えば、google guavaのOptionalは適切なor()操作(JDK9と同様or()サポートしています。例:

return serviceA(args)
  .or(() -> serviceB(args))
  .or(() -> serviceC(args))
  .or(() -> serviceD(args));

(各サービスはjava.util.Optionalではなくcom.google.common.base.Optional返します)。