java – Optional Java 8 use with Stream :: flatMap

I am adding this second answer based on a modification proposed by the user srborlongan to my other answer . I think the proposed technique is interesting, but it wasn’t really suitable as a modification to my answer. Others accepted and the proposed change was voted down. (I wasn’t one of the voters.) The technique has the merit, though. It would have been better if srborlongan had posted his answer. This hasn’t happened yet, and I didn’t want the technique to get lost in the mists of StackOverflow’s rejected edit history, so I decided to bring it up as a separate answer.

Basically the technique is to use some of the methods Optional intelligently to avoid having to use a ternary operator (? :) or an if / else statement.

My inline example would be rewritten like this:

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

An example of mine using a helper method would be rewritten like this:

/**
 * 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) {
    return opt.map(Stream::of)
              .orElseGet(Stream::empty);
}

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

COMMENT

Let’s compare the original versions vs the directly modified ones:

// original
.flatMap(o -> o.isPresent() ? Stream.of(o.get()) : Stream.empty())

// modified
.flatMap(o -> o.map(Stream::of).orElseGet(Stream::empty))

The original is a direct approach, if in a workmanlike manner: we get a Optional<Other>; if it has a value, we return a stream that contains that value, and if it has no value, we return an empty stream. Quite simple and easy to explain.

Editing is smart and has the advantage of avoiding conditionals. (I know some people dislike the ternary operator, if used incorrectly it can really make the code difficult to understand). However, sometimes things can be too clever. The modified code also starts with Optional<Other>. Then call Optional.map which is defined as follows:

If there is a value, apply the mapping function provided and, if the result is non-null, return an Optional describing the result. Otherwise, return a blank Optional.

The call map(Stream::of) returns a Optional<Stream<Other>>. If an Optional value was present in the input, the returned Optional contains a stream containing the single result Other. But if the value was not present, the result is an empty Optional.

Subsequently, the call to orElseGet(Stream::empty) returns a value of type Stream<Other>. If its input value is present, it gets the value, which is the single element Stream<Other>. Otherwise (if the input value is absent) it returns a Stream<Other> empty. So the result is correct, the same as the original conditional code.

In the comments discussing my answer regarding the rejected modification, I had described this technique as “more concise but also more obscure”. I keep myself in mind. It took me a while to figure out what he was doing, and it took me a while to write the description above what he was doing. The subtlety of the key is the transformation from Optional<Other> to Optional<Stream<Other>>. Once you beat it, it makes sense, but it wasn’t obvious to me.

I will recognize, however, that things that are initially obscure can become idiomatic over time. It could be that this technique ends up being the best way in practice, at least until when Optional.stream it is not added (if it ever does).

UPDATE: Optional.stream was added to JDK 9.

Leave a comment