Using Java 8's Optional with Stream::Flatmap

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 Optionals (unless you wish to transform them to nulls).

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:

  1. flatMap as posited the question
  2. filter and map as described in the question
  3. mapMulti 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).































ApproachFull ListHalf Empty ListEmpty List
flatMap207.219 ± 1.176175.355 ± 4.955142.986 ± 2.821
filter/map12.856 ± 0.37512.086 ± 0.4516.856 ± 0.143
mapMulti13.990 ± 0.35311.685 ± 0.2767.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



Leave a reply



Submit