I have a id
value which can be null
. Then I need to call some service with this id
to get a list of trades and fetch the first not null
trade from the list.
Currently I have this working code
Optional.ofNullable(id)
.map(id -> service.findTrades(id))
.flatMap(t -> t.stream().filter(Objects::nonNull).findFirst())
.orElse(... default value...);
Is it possible to implement a line with a flatMap
call more elegantly? I don't want to put much logic in one pipeline step.
Initially I expected to implement the logic this way
Optional.ofNullable(id)
.flatMap(id -> service.findTrades(id))
.filter(Objects::nonNull)
.findFirst()
.orElse(... default value...);
But Optional.flatMap
doesn't allow to flatten a list into a set of it's elements.
Third and probably the most useful way of creating an Optional instance is by using the ofNullable() method of java. util. Optional class which allows you to create an Optional object that may hold a null value as shown in the following example: Optional<Person> op = Optional.
Map. FlatMap. Map will apply the mapping function and if the result is not null – will return Optional describing the result. Flatmap will apply the mapping function and if the result is not null and result already being an optional – flatmap does not wrap with additional Optional.
In Java 8 Streams, the flatMap() method applies operation as a mapper function and provides a stream of element values. It means that in each iteration of each element the map() method creates a separate new stream. By using the flattening mechanism, it merges all streams into a single resultant stream.
I don't know if this is elegant or not, but here's a way to transform the optional in a stream before initiating the stream pipeline:
Trade trade = Optional.ofNullable(id)
.map(service::findTrades)
.map(Collection::stream)
.orElse(Stream.empty()) // or orElseGet(Stream::empty)
.filter(Objects::nonNull)
.findFirst()
.orElse(... default value...);
In Java 9, Optional
will have a .stream()
method, so you will be able to directly convert the optional into a stream:
Trade trade = Optional.ofNullable(id)
.stream() // <-- Stream either empty or with the id
.map(service::findTrades) // <-- Now we are at the stream pipeline
.flatMap(Collection::stream) // We need to flatmap, so that we
.filter(Objects::nonNull) // stream the elements of the collection
.findFirst()
.orElse(... default value...);
There is a better way to do it by StreamEx
StreamEx.ofNullable(id)
.flatMap(id -> service.findTrades(id))
.filter(Objects::nonNull)
.findFirst()
.orElse(... default value...);
I just saw: "As Stuart Marks says it, Rule #4: It's generally a bad idea to create an Optional for the specific purpose of chaining methods from it to get a value.." in the comments under another question:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With