Optional

java.util.Optional<T>

A functional way to deal with errors

“You can’t always get what you want.”

—Rolling Stones

For instance

streamOfStrings.max((a, b) -> a.length() - b.length())

Reduces a stream down to a single maximum value, in this case, the longest string.

But what should this return if the stream is empty?

Optional to the rescue

An Optional<T> is kind of like an Stream<T> of either zero or one elements.

If it has one element the value is said to be “present”. Otherwise the Optional is “empty”.

The max from the previous slide returns an Optional<String>.

The Optional either contains the longest string in the stream or is empty if there was no such string (because the stream was empty).

Doing stuff with the value

Like Streams, Optionals give us a way to describe a computation by chaining together operations.

Most methods that return another Optional, when invoked on an empty Optional just produce another empty Optional.

filter

Optional<T> filter(Predicate<? super T> predicate)

Reurn an Optional<T> with the same value (maybe the same one) if the value matches the predicate or an empty Optional<T> if either the predicate doesn’t match or the original Optional was empty.

Optional.of(someString).filter(s -> s.startsWith("x"))

map

<U> Optional<U> map(Function<? super T,? extends U> mapper)

From an Optional<T> produce an Optional<U> containing the original value as transformed by mapper or an empty Optional<U> if the original Optional was empty.

I.e. we unwrap the original Optional in order to pass the value to mapper which produces a new value which is then wrapped back in another Optional.

map example

xs.max(cmp).map(x -> new Whatever(x))

Returns an Optional<Whatever>.

flatMap

<U> Optional<U> flatMap(
  Function<? super T,? extends Optional<? extends U>> mapper
)

Like map but the function returns an Optional<U> rather than a U. The result only has one level of Optional.

I.e. we unwrap the first Optional in order to pass the value to mapper which then produces a new Optional.

flatMap example

Stream<X> xs = ...
Stream<Y> ys = ...
xs.max(cmp).flatMap(x -> ys.findFirst(y -> y.betterThan(x)))

Returns at Optional<Y> since findFirst returns an Optional<Y>.

xs.max(cmp).map(x -> ys.findFirst(y -> y.betterThan(x)))

Would return an Optional<Optional<Y>> which is almost never what you want.

or

Optional<T> or(
  Supplier<? extends Optional<? extends T>> supplier
)

Reurn an Optional<T> with the same value (maybe the same one) if not empty, or the Optional returned by supplier.

get

T get()

Unwrap the Optional and return the value. Explodes (throws an exception) if the Optional is empty.

orElse

T orElse(T other)

Unwrap the Optional and return the value, if present. Otherwise return other.

maybeName.orElse("anonymous")

orElseGet

T orElseGet(Supplier<? extends T> supplier)

Unwrap the Optional and return the value, if present. Otherwise invoke supplier and return whatever it returns.

maybeName.orElseGet(this::generatePseudonym)

ifPresent

void ifPresent(Consumer<? super T> action)

Run action with the value if one is present.

maybeName.ifPresent(System.out::println);

ifPresentOrElse

void ifPresentOrElse(
  Consumer<? super T> action,
  Runnable emptyAction)

Run action with the value if one is present. Otherwise run the emptyAction.

maybeName.ifPresentOrElse(
  name -> System.out.println("Hello, " + name + ".")
  () -> System.out.println("Hello.")
);

ifPresent

boolean ifPresent()

Returns true if the Optional is not empty, false otherwise.

A bridge to procedural code.