Java 8のOptionalをStream::flatMapで使用する 質問する

Java 8のOptionalをStream::flatMapで使用する 質問する

新しい Java 8 ストリーム フレームワークとその仲間により、非常に簡潔な Java コードが作成できますが、一見単純に見えても簡潔に実行するのが難しい状況に遭遇しました。

List<Thing> thingsおよび メソッド について考えます。を にマップし、最初の を取得したいOptional<Other> resolve(Thing thing)と思います。ThingOptional<Other>Other

明らかな解決策は を使用することですthings.stream().flatMap(this::resolve).findFirst()が、flatMapではストリームを返す必要があり、メソッドOptionalがありませんstream()(または であるCollectionか、 を に変換するか として表示するメソッドを提供しますCollection)。

私が思いつく最善のものはこれです:

things.stream()
    .map(this::resolve)
    .filter(Optional::isPresent)
    .map(Optional::get)
    .findFirst();

しかし、それは非常に一般的なケースであるにもかかわらず、非常に冗長に思えます。

もっと良いアイデアをお持ちの方はいらっしゃいますか?

ベストアンサー1

Java9 について

Optional.streamJDK 9 に追加されました。これにより、ヘルパー メソッドを必要とせずに次の操作を実行できるようになります。

Optional<Other> result =
    things.stream()
          .map(this::resolve)
          .flatMap(Optional::stream)
          .findFirst();

Java 8

はい、これは API の小さな穴で、 をOptional<T>0 または 1 の長さに変換するのがやや不便ですStream<T>。次のようにすることができます。

Optional<Other> result =
    things.stream()
          .map(this::resolve)
          .flatMap(o -> o.isPresent() ? Stream.of(o.get()) : Stream.empty())
          .findFirst();

ただし、三項演算子を内部に置くのはflatMap少し面倒なので、これを行うための小さなヘルパー関数を記述する方がよい場合があります。

/**
 * Turns an Optional<T> into a Stream<T> of length zero or one depending upon
 * whether a value is present.
 */
static <T> Stream<T> streamopt(Optional<T> opt) {
    if (opt.isPresent())
        return Stream.of(opt.get());
    else
        return Stream.empty();
}

Optional<Other> result =
    things.stream()
          .flatMap(t -> streamopt(resolve(t)))
          .findFirst();

resolve()ここでは、別の操作を行う代わりに、呼び出しをインライン化していますmap()が、これは好みの問題です。

おすすめ記事