Optional
Optional says explicitly: the result may be absent
A method sometimes cannot find a value. Returning null communicates this implicitly:
the calling code has to remember the check on its own. Optional<T>
makes the absence of a result part of the return type.
Optional<String> findName(int id) {
if (id == 1) {
return Optional.of("Alice");
}
return Optional.empty();
}
Optional.of(value) is used for a value that is guaranteed to be non-null,
Optional.ofNullable(value) also accepts null,
and Optional.empty() creates an empty result.
Work with the value through Optional operations
Instead of a manual “check — extract — transform” sequence,
it is often more convenient to continue the computation through map, filter,
and flatMap.
Optional<Integer> length = findName(1)
.filter(name -> !name.isBlank())
.map(String::length);
If the name exists and is not blank, the result is an Optional containing the length.
If the value was absent or failed the filter, the result remains empty.
A default value or an exception
orElse returns a fallback value,
orElseGet computes it through a Supplier only when needed,
and orElseThrow reports the missing value with an exception.
String name = findName(10)
.orElse("Unknown");
If creating the fallback value is expensive or has a side effect,
orElseGet is usually the better choice:
the argument of orElse is evaluated before the method call,
even when the Optional already contains a value.
Do not turn Optional back into a hidden null
The get() method exists, but calling it directly without a guarantee that a value is present
brings back the same problem: instead of a NullPointerException,
you can now get a NoSuchElementException.
Intent is usually expressed better with orElse, orElseThrow,
ifPresent, or a chain of transformations.
Optional is especially useful as a method return type.
It is not a universal replacement for every null in a program,
but a way to tell calling code explicitly: “a result may be absent here.”