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 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 into a Stream of length zero or one depending upon
* whether a value is present.
*/
static Stream streamopt(Optional opt) {
return opt.map(Stream::of)
.orElseGet(Stream::empty);
}
Optional 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
; 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
. 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
. 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
. If its input value is present, it gets the value, which is the single element Stream
. Otherwise (if the input value is absent) it returns a Stream
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
to Optional
. 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.