247. Chaining the Optional and Stream APIs

Starting with JDK 9, we can refer to an Optional instance as Stream by applying the Optional.stream() method.

This is quite useful when we have to chain the Optional and Stream APIs. The Optional.stream() method returns a Stream of one element (the value of Optional) or an empty Stream (if Optional has no value). Furthermore, we can use all of the methods that are available in the Stream API.

Let's assume that we have a method for fetching books by ISBN (if no book matches the given ISBN, then this method returns an empty Optional object):

public Optional<Book> fetchBookByIsbn(String isbn) {
// fetching book by the given "isbn" can return null
Book book = ...;

return Optional.ofNullable(book);
}

In addition to this, we loop a List of ISBNs and return  List of Book as follows (each ISBN is passed through the fetchBookByIsbn() method):

// Avoid
public List<Book> fetchBooks(List<String> isbns) {

return isbns.stream()
.map(this::fetchBookByIsbn)
.filter(Optional::isPresent)
.map(Optional::get)
.collect(toList());
}

The focus here is on the following two lines of code:

.filter(Optional::isPresent)
.map(Optional::get)

Since the fetchBookByIsbn() method can return empty Optional classes, we must ensure that we eliminate them from the final result. For this, we call Stream.filter() and apply the Optional.isPresent() function to each Optional object returned by fetchBookByIsbn(). So, after filtering, we have only Optional classes with present values. Furthermore, we apply the Stream.map() method for unwrapping these Optional classes to Book. Finally, we collect the Book objects in  List.

But we can accomplish the same thing more elegantly using Optional.stream(), as follows:

// Prefer
public List<Book> fetchBooksPrefer(List<String> isbns) {

return isbns.stream()
.map(this::fetchBookByIsbn)
.flatMap(Optional::stream)
.collect(toList());
}
Practically, in cases like these, we can use Optional.stream() to replace filter() and map() with flatMap().

Calling Optional.stream() for each Optional<Book> returned by fetchBookByIsbn() will result in  Stream<Book> containing a single Book object or nothing (an empty stream). If Optional<Book> doesn't contain a value (is empty), then Stream<Book> is also empty. Relying on flatMap() instead of map() will avoid a result of the Stream<Stream<Book>> type.

As a bonus, we can convert Optional into List as follows:

public static<T> List<T> optionalToList(Optional<T> optional) {
return optional.stream().collect(toList());
}
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset