Although Java 9 has already been released, this post is about converting an optional collection to the Streams API introduced in Java 8.

Suppose some person could have zero, one or more cars and it is represented by the Person class below (some code omitted).

public class Person {

    private String name;

    .
    .
    .

    public Optional> getCars() {
        return Optional.ofNullable(cars);
    }

    .
    .
    .

}

Now we create a list of people and we want to get Mark’s cars.

Person mark = new Person("Mark");

List people = ...

How can we do that using the Streams API, since the getCars() method return an Optional?

One possibility is to filter people’s list by Mark’s name, filter the Optional if it is present or not and map its wrapped value (our cars list):

Collection markCars = people
                .stream()
                .filter(person -> "Mark".equals(person.getName()))
                .findFirst()
                .map(Person::getCars)
                .filter(Optional::isPresent)
                .map(Optional::get)
                .orElse(Collections.emptyList());

At this moment we reached the reason of this blog post. And how can we get all people’s cars? The idea here is to use the flatMap() operation unwrapping the Optional to the collection’s stream when it is present or getting an empty stream when it isn’t present:

Collection allPeopleCars = people
                .stream()
                .map(Person::getCars)
                .flatMap(mayHaveCars -> mayHaveCars.isPresent() ? mayHaveCars.get().stream() : Stream.empty())
                .collect(Collectors.toList());

We can do better and replace the above solution to be more functional using method references:

Collection allPeopleCars = people
                .stream()
                .map(Person::getCars)
                .flatMap(mayHaveCars -> mayHaveCars.map(Collection::stream).orElse(Stream.empty()))
                .collect(Collectors.toList());

If you use IntelliJ IDEA as your favorite IDE, it has an inspection that helps replacing Optional.isPresent() with a functional expression:

Collection allPeopleCars = people
                .stream()
                .map(Person::getCars)
                .flatMap(mayHaveCars -> mayHaveCars.map(Collection::stream).orElseGet(Stream::empty))
                .collect(Collectors.toList());

P.S. In Java 9, the stream() method was added to the Optional API, so we can rewrite the above stream pipeline into the following one:

Collection allPeopleCars = people
                .stream()
                .map(Person::getCars)
                .flatMap(Optional::stream)
                .flatMap(Collection::stream)
                .collect(Collectors.toList());

In case you are interested, this post on the IntelliJ IDEA blog has some good tips when working with Java 8.