Improvements to Optional in Java 9
Indrek Ots
by Indrek Ots
2 min read

Categories

  • articles

Tags

  • java
  • java 9
  • optional

Optionals were introduced to Java in version 8. If used correctly, they can help you avoid unintentional NullPointerExceptions. Essentially, an Optional is a container object which may or may not contain a non-null a value. Combined with lambda expressions, you can write concise code that avoids explicit null checks.

Optional<Book> bookOptional = findBook("The War of the Worlds");
Book book = bookOptional.orElseGet(Book::defaultBook);

Java 9 introduced a couple of improvements to the Optional class.

Stream from Optional

Optional::stream allows you to transform an Optional to a Stream. If a value is present, the returned Stream will contain that value. Otherwise an empty Stream is returned. You might be thinking how can that be useful? We use Streams to manipulate collections of data. How can a Stream that contains at most one element be useful?

In a Stream processing pipeline we can transform Optionals into Streams and flatmap them into a single Stream containing only the values that are present. Let’s look at the following example.

List<Book> books = ...

List<Author> ghostwriters = books.stream()
  .map(Book::getGhostWriter)
  .flatMap(Optional::stream)
  .collect(toList());

Since every book doesn’t have a ghostwriter, getGhostWriter() returns an Optional of Author (Optional<Author>). For each book, Optional::stream creates a new Stream and flatmap will ensure that all Streams are merged together. Essentially, we’re getting rid of empty Optionals.

You could do it in Java 8 with a lambda expression but Optional::stream is more succinct.

List<Book> books = ...

List<Author> ghostwriters = books.stream()
  .map(Book::getGhostWriter)
  .flatMap(o -> o.map(Stream::of).orElseGet(Stream::empty))
  .collect(toList());

Optional::or

Optional::or will either return the current Optional if a value is present. Otherwise an Optional produced by the provided supplier function is returned. To make things more clear, let’s have a look at the following example.

findBook().or(() -> findBookFromWeb());

If findBook() does not find anything, findBookFromWeb() gets called. Since the return value is always an Optional, we can build a lazily loaded chain of method calls.

public Optional<Book> findBook(String title) {
  return findBookFromDatabase(title)
    .or(() -> findBookFromLocalLibrary(title))
    .or(() -> findBookFromWeb(title));
}

Back in Java 8 you had to go through some ceremony to achieve something similar.

Optional::ifPresentOrElse

The final addition to Optionals in Java 9 is the Optional::ifPresentOrElse method. By accepting a consumer function and a runnable, it can be used to cover the case where the value is present as well as the case where the Optional is empty.

findBook(title).ifPresentOrElse(
    this::increaseReaderCount,
    () -> log.warn("Tried to look for a book which does not exist!"));

Summary

Three new methods were added to the Optional class in Java 9. Optional::stream allows you to transform an Optional into a Stream of one element or an empty Stream. Optional::or returns the current Optional if a value is present, otherwise an Optional produced by the supplier function is returned. Optional::ifPresentOrElse can be used to cover the value present as well as the value missing cases.