Using Java 8's Optional with Stream::flatMap
Java 9
Optional.stream
has been added to JDK 9. This enables you to do the following, without the need of any helper method:
Optional<Other> result =
things.stream()
.map(this::resolve)
.flatMap(Optional::stream)
.findFirst();
Java 8
Yes, this was a small hole in the API, in that it's somewhat inconvenient to turn an Optional<T>
into a zero-or-one length Stream<T>
. You could do this:
Optional<Other> result =
things.stream()
.map(this::resolve)
.flatMap(o -> o.isPresent() ? Stream.of(o.get()) : Stream.empty())
.findFirst();
Having the ternary operator inside the flatMap
is a bit cumbersome, though, so it might be better to write a little helper function to do 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) {
if (opt.isPresent())
return Stream.of(opt.get());
else
return Stream.empty();
}
Optional<Other> result =
things.stream()
.flatMap(t -> streamopt(resolve(t)))
.findFirst();
Here, I've inlined the call to resolve()
instead of having a separate map()
operation, but this is a matter of taste.
Java8 :: flatMap in optional
See the signature of flatMap
:
public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper)
The Function
is supposed to return an Optional
, so in order to use it, you'll need to write:
Optional.ofNullable(project)
.map(prjct-> prjct.getApplciationType())
.flatMap(appType1 -> Optional.ofNullable(appType1.getDirectory()))
.ifPresent(e -> System.out.println(e));
Of course, using map
makes more sense in this example (as in your first snippet, which passes compilation).
Java's flatMap on list of list of optional integers
It should be:
List<Integer> flattened =
list
.stream()
.filter (Optional::isPresent)
.map(Optional::get)
.collect(Collectors.toList());
Your flatMap
expects a function that transforms a Stream
element to a Stream
. You should use map
instead (to extract the value of the Optional
). In addition, you need to filter out empty Optional
s (unless you wish to transform them to null
s).
Without the filtering:
List<Integer> flattened =
list
.stream()
.map(o -> o.orElse(null))
.collect(Collectors.toList());
How to convert an Optional T into a Stream T ?
In Java-9 the missing stream()
method is added, so this code works:
Stream<String> texts = optional.stream();
See JDK-8050820. Download Java-9 here.
Flattening a list of elements in Java 8 Optional pipeline
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...);
how to handle Optional Object in java streams api?
Just merge the two stream pipelines i.e.
List<Employee> employees = Stream.of(empIds)
.map(employeeRepository::findById)
.filter(Optional::isPresent)
.map(Optional::get)
//.filter(e->e !=null) not needed as it's redundant
.filter(e->e.getSalary()>200000)
.collect(Collectors.toList());
What is the difference between Optional.flatMap and Optional.map?
Use map
if the function returns the object you need or flatMap
if the function returns an Optional
. For example:
public static void main(String[] args) {
Optional<String> s = Optional.of("input");
System.out.println(s.map(Test::getOutput));
System.out.println(s.flatMap(Test::getOutputOpt));
}
static String getOutput(String input) {
return input == null ? null : "output for " + input;
}
static Optional<String> getOutputOpt(String input) {
return input == null ? Optional.empty() : Optional.of("output for " + input);
}
Both print statements print the same thing.
java lambda - how to traverse optional list/stream of optionals
First, check if the Optional
is present. If yes, then stream the list and filter the non-empty ones and print each of them.
optionalList.ifPresent(list -> list.stream()
.filter(Optional::isPresent)
.map(Optional::get)
.forEach(System.out::println));
Almost similar for the stream case too
optionalStream.ifPresent(stream -> stream
.filter(Optional::isPresent)
.map(Optional::get)
.forEach(System.out::println));
Regarding efficiency: Isn’t .filter(Optional::isPresent).map(Optional::get) better than .flatmap(Optional::stream)?
I got curious and wrote a simple micro-benchmark using JMH.
And it turns out that there is a quite severe performance penalty for using flatMap(Optional::stream)
over filter(Optional::isPresent).map(Optional::get)
.
Java 16 introduced mapMulti
which is similar to flatMap
in usage and has performance characteristics very close to those of filter
/map
.
Each of my benchmark methods takes a list of Optional<Integer>
and computes the sum of all present values.
I implemented three approaches:
flatMap
as posited the questionfilter
andmap
as described in the questionmapMulti
introduced in JDK 16.
Note that I did not make use of the flatMapToInt
or mapMultiToInt
methods, which are probably more efficient, because I didn't want to focus on the streams-over-wrapper objects aspect and just compare the usage of streams over Optional
objects.
For all approaches I ran the benchmark with a full list (all values present), a half empty list (every second value present), and an entirely empty list (each optional is empty). The lists are all the same length (arbitrarily picked 10 000 elements each).
The unit for the values is us/op (microseconds per operation, meaning one full stream evaluation).
Approach | Full List | Half Empty List | Empty List |
---|---|---|---|
flatMap | 207.219 ± 1.176 | 175.355 ± 4.955 | 142.986 ± 2.821 |
filter /map | 12.856 ± 0.375 | 12.086 ± 0.451 | 6.856 ± 0.143 |
mapMulti | 13.990 ± 0.353 | 11.685 ± 0.276 | 7.034 ± 0.199 |
Java 8 flatMap + Optional.of doesn't compile
There is no need to deal with Optional
here.
The simplest straight-forward solution is to use filter
List<String> result = x.stream()
.filter(val -> !val.equals("b"))
.collect(Collectors.toList());
If you insist on using flatMap
, you should simply use Stream
instead of Optional
:
List<String> result = x.stream().flatMap(
val -> val.equals("b")? Stream.empty(): Stream.of(val))
.collect(Collectors.toList());
If you have to deal with an operation that unavoidably produces an Optional
, you will have to convert it to a Stream
for using Stream.flatMap
:
List<String> result = x.stream()
.map(val -> val.equals("b") ? Optional.<String>empty() : Optional.of(val))
.flatMap(o->o.map(Stream::of).orElse(Stream.empty()))
.collect(Collectors.toList());
Related Topics
Differences Between System.Out.Println() and Return in Java
What Is the Maximum Depth of the Java Call Stack
What Is the Purpose of Java's Unary Plus Operator
Getting Fonts, Sizes, Bold,...Etc
Why Does Priorityqueue.Tostring Return the Wrong Element Order
Spring @Transactional - Isolation, Propagation
Date and Time Conversion to Some Other Timezone in Java
How to Create a Directory in Java
Java 8: Performance of Streams VS Collections
Differencebetween Swing and Awt
What Could Cause Java.Lang.Reflect.Invocationtargetexception
Why Call Super() in a Constructor
Redirect Console Output to String in Java
How to Add an Actionlistener Onto a Jbutton in Java