In Java 8, a new class named Optional
was introduced. Or rather in the word-style of Douglas Adams, “in the beginning null was created. This made a lot of people angry and was widely regarded as a bad move“. Optional
was introduced to alleviate some of that anger.
Optional
relieved developers of the grief of null checks and the “fun” of a NullPointerException
popping up when failing to null check.
In Java 8, the Optional
already had very useful methods:
of
– Wrap the non-null value into anOptional
.ofNullable
– Wrap and return anOptional
of the current value, if current value is null, returnOptional.empty()
isPresent
– Checks and returns a boolean indicating the presence of a non-null value in theOptional
.ifPresent
– Checks and invokes the specifiedConsumer
instance upon the presence of a non-null value in theOptional
.get
– Fetch the value in theOptional
if it is not null, else throw aNoSuchElementException
orElse
– Fetch the value in theOptional
if it is not null, else return the other element passed in.orElseGet
– Fetch the value in theOptional
if it is not null, else return invoke the otherSupplier
to fetch an element instead.orElseThrow
– Fetch the value in theOptional
if it is not null, else throw the passed inException
.filter
– If the value exists, test the filteringPredicate
on it and if true return result wrapped in anOptional
, else returnOptional.empty()
.map
– If the value exists, apply the mappingFunction
to it and return any non-null result wrapped in anOptional
, else returnOptional.empty()
.flatMap
– If the value exists, apply theOptional
-bearing mappingFunction
to it and return any non-null result wrapped in anOptional
, else returnOptional.empty()
.
Java 9 changes
ifPresentOrElse
– Checks and returns a boolean indicating the presence of a non-null value in theOptional
, or else, invokes theRunnable
action.or
– Wrap and return anOptional
of the current value if not null; if current value is null, returnOptional
by invoking the specifiedSupplier
stream
– Returns a sequential stream containing only the value, if the value is non-null.
Optional::ifPresentOrElse
Consider a situation where the code is to either run a Consumer if the value exists or else run a different action. This is not possible in the Java 8 Optional
behavior. Optional
in Java 8 provides an orElse
or an orElseGet
method, both of which actually return an unwrapped value, rather than act as an execution block.
Pre-Java 8 :
if(preference != null) {
callPresenceAction();
} else {
callAbsenceAction();
}
In Java 8 :
if(optionalPreference.isPresent()) {
callPresenceAction();
} else {
callAbsenceAction();
}
or
optionalPreference.ifPresent(callPresenceConsumer());
// orElseGet returns a non-optional value
// it cannot be used to simply execute an action.
Preference p = optionalPreference.orElseGet(callAbsenceSupplier());
In Java 9 :
optionalPreference
.ifPresentOrElse(presenceAction,absenceAction);
Optional::or
Per the Java 8 API, both the orElse
and the orElseGet
do not return an Optional
, rather return the unwrapped value. It is possible that such a value is null. The or
method is introduced as a means to execute a supplier on absence of an unwrapped value in the container, and returns an Optional, rather than the unwrapped value.
Pre-Java 8 :
Preference preference = findPreference(name);
if(preference == null) {
preference = createPreference(name, description);
}
// preference can still be null !!!
In Java 8 :
Preference preference =
findOptionalPreference(name)
.orElseGet(getPreferenceSupplier(name, description));
// preference can still be null !!!
In Java 9 :
Optional optionalPreference =
findOptionalPreference(name)
.or(getOptionalPreferenceSupplier(name, description));
// optional preference, so, protected from being null !!!
Optional::stream
Given a situation where a stream or collection of Optional
s exist, and we need to extract values from each, if they contain non-null values. Optional::stream
returns a stream with a single non-null value if the Optional
has a non-null value, or returns an empty stream otherwise.
Pre-Java 8 :
List preferences = new ArrayList();
for (String preferenceName : PREFERENCE_NAMES) {
Preference aPreference = findPreference(preferenceName);
if (aPreference != null) {
preferences.add(aPreference);
}
}
In Java 8 :
List preferences =
PREFERENCE_NAMES.stream()
.map(preferenceName -> findOptionalPreference(preferenceName))
.filter(Optional::isPresent)
.map(Optional::get)
.collect(toList());
In Java 9 :
List preferences =
PREFERENCE_NAMES.stream()
.map(preferenceName -> findOptionalPreference(preferenceName))
.flatMap(Optional::stream)
.collect(toList());
That’s a wrap on the Optional
changes in Java 9. Hope this post was helpful.