148

I've been working with the new Optional type in Java 8, and I've come across what seems like a common operation that isn't supported functionally: an "orElseOptional"

Consider the following pattern:

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);
}

There are many forms of this pattern, but it boils down to wanting an "orElse" on an optional that takes a function producing a new optional, called only if the current one does not exist.

It's implementation would look like this:

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

I'm curious if there's a reason such a method doesn't exist, if I'm just using Optional in an unintended way, and what other ways people have come up with to deal with this case.

I should say that I think that solutions involving custom utility classes/methods aren't elegant because people working with my code won't necessarily know they exist.

Also, if anyone knows, will such a method be included in JDK 9, and where might I propose such a method? This seems like a pretty glaring omission to the API to me.

4

6 に答える 6

99

これは JDK 9 の一部でありorSupplier<Optional<T>>. あなたの例は次のようになります。

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

詳細については、Javadocまたは私が書いたこの投稿を参照してください。

于 2016-07-25T05:56:50.527 に答える
36

きれいではありませんが、これはうまくいきます:

return serviceA(args)
  .map(Optional::of).orElseGet(() -> serviceB(args))
  .map(Optional::of).orElseGet(() -> serviceC(args))
  .map(Optional::of).orElseGet(() -> serviceD(args));

.map(func).orElseGet(sup)で使用するのに非常に便利なパターンですOptional。「これOptionalに値が含まれている場合vは私func(v)に、そうでない場合は私にsup.get()」という意味です。

この場合、呼び出しserviceA(args)て を取得しOptional<Result>ます。値がOptional含まれている場合vは を取得しますOptional.of(v)が、空の場合は を取得しますserviceB(args)。より多くの代替品で繰り返します。

このパターンの他の用途は次のとおりです。

  • .map(Stream::of).orElseGet(Stream::empty)
  • .map(Collections::singleton).orElseGet(Collections::emptySet)
于 2015-03-02T23:26:32.230 に答える
29

おそらく、これはあなたが求めているものです: 1 つの Optional または別の値から値を取得する

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

result = Optional.ofNullable(serviceA().orElseGet(
                                 () -> serviceB().orElseGet(
                                     () -> serviceC().orElse(null))));
于 2015-03-02T20:10:42.167 に答える