新しい Java 8 ストリーム フレームワークとその仲間により、非常に簡潔な Java コードが作成できますが、一見単純に見えても簡潔に実行するのが難しい状況に遭遇しました。
List<Thing> things
および メソッド について考えます。を にマップし、最初の を取得したいOptional<Other> resolve(Thing thing)
と思います。Thing
Optional<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.stream
JDK 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()
が、これは好みの問題です。