3

Given a sequence of Supplier<Option<T>> -- e.g., a list of method references -- what's the idiomatic way to get the first defined result, if any? Ideally without invoking any more suppliers after the first successful result.

What I have now is:

Stream<Supplier<Option<Foo>>> suppliers = Stream.of(
  bar::fooOption,
  baz::fooOption,
  qux::fooOption
);

Option<Foo> firstDefined = suppliers.map(Supplier::get)
  .find(Option::isDefined)
  .flatMap(Function.identity());

but it seems like there ought to be a way to flatmap that even flatter.

David Moles
  • 48,006
  • 27
  • 136
  • 235

2 Answers2

2

I can only see an alternative solution with equal number of steps as yours.

Option<Foo> firstDefined = suppliers.map(Supplier::get)
        .find(Option::isDefined)
        .map(Option::get);

If you can do with a simple map instead of a flatMap, use that instead, as it will be usually faster, especially on multi-valued monadic containers. There's probably not much difference though for 0/1 valued monads, like Option, perhaps on the contrary, it might be a tad slower in this case, as it creates an additional Option.

Nándor Előd Fekete
  • 6,988
  • 1
  • 22
  • 47
2

You want the flatMap :)

 suppliers.flatMap(_.get).headOption
Dima
  • 39,570
  • 6
  • 44
  • 70
  • This is probably the cleanest. I'm curious about performance in light of [Nándor's answer](https://stackoverflow.com/a/45290259/27358), but not curious enough to actually benchmark it. :) – David Moles Jul 25 '17 at 16:56
  • @DavidMoles don't think performance difference between map and flatmap is worth considering. `Option.get` is generally considered "code smell" in FP on the other hand. So, my advice would be the opposite: always prefer `flatMap` (or `flatten`) to "unwrapping" options explicitly. – Dima Jul 25 '17 at 17:15