“You can’t always get what you want.”
—Rolling Stones
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?
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).
Like Stream
s, Optional
s 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
examplexs.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
exampleStream<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.