Uses for Optional
JavaJava 8OptionalJava Problem Overview
Having been using Java 8 now for 6+ months or so, I'm pretty happy with the new API changes. One area I'm still not confident in is when to use Optional
. I seem to swing between wanting to use it everywhere something may be null
, and nowhere at all.
There seem to be a lot of situations when I could use it, and I'm never sure if it adds benefits (readability / null safety) or just causes additional overhead.
So, I have a few examples, and I'd be interested in the community's thoughts on whether Optional
is beneficial.
1 - As a public method return type when the method could return null
:
public Optional<Foo> findFoo(String id);
2 - As a method parameter when the param may be null
:
public Foo doSomething(String id, Optional<Bar> barOptional);
3 - As an optional member of a bean:
public class Book {
private List<Pages> pages;
private Optional<Index> index;
}
4 - In Collections
:
In general I don't think:
List<Optional<Foo>>
adds anything - especially since one can use filter()
to remove null
values etc, but are there any good uses for Optional
in collections?
Any cases I've missed?
Java Solutions
Solution 1 - Java
The main design goal of Optional
is to provide a means for a function returning a value to indicate the absence of a return value. See this discussion. This allows the caller to continue a chain of fluent method calls.
This most closely matches use case #1 in the OP's question. Although, absence of a value is a more precise formulation than null since something like IntStream.findFirst
could never return null.
For use case #2, passing an optional argument to a method, this could be made to work, but it's rather clumsy. Suppose you have a method that takes a string followed by an optional second string. Accepting an Optional
as the second arg would result in code like this:
foo("bar", Optional.of("baz"));
foo("bar", Optional.empty());
Even accepting null is nicer:
foo("bar", "baz");
foo("bar", null);
Probably the best is to have an overloaded method that accepts a single string argument and provides a default for the second:
foo("bar", "baz");
foo("bar");
This does have limitations, but it's much nicer than either of the above.
Use cases #3 and #4, having an Optional
in a class field or in a data structure, is considered a misuse of the API. First, it goes against the main design goal of Optional
as stated at the top. Second, it doesn't add any value.
There are three ways to deal with the absence of a value in an Optional
: to provide a substitute value, to call a function to provide a substitute value, or to throw an exception. If you're storing into a field, you'd do this at initialization or assignment time. If you're adding values into a list, as the OP mentioned, you have the additional choice of simply not adding the value, thereby "flattening" out absent values.
I'm sure somebody could come up with some contrived cases where they really want to store an Optional
in a field or a collection, but in general, it is best to avoid doing this.
Solution 2 - Java
I'm late to the game but for what it's worth, I want to add my 2 Cents. They go against the design goal of Optional
, which is well summarized by Stuart Marks's answer, but I'm still convinced of their validity (obviously).
Use Optional Everywhere
In General
I wrote an entire blog post about using Optional
but it basically comes down to this:
- design your classes to avoid optionality wherever feasibly possible
- in all remaining cases, the default should be to use
Optional
instead ofnull
- possibly make exceptions for:
- local variables
- return values and arguments to private methods
- performance critical code blocks (no guesses, use a profiler)
The first two exceptions can reduce the perceived overhead of wrapping and unwrapping references in Optional
. They are chosen such that a null can never legally pass a boundary from one instance into another.
Note that this will almost never allow Optional
s in collections which is almost as bad as null
s. Just don't do it. ;)
Regarding your questions
- Yes.
- If overloading is no option, yes.
- If other approaches (subclassing, decorating, ...) are no option, yes.
- Please no!
Advantages
Doing this reduces the presence of null
s in your code base, although it does not eradicate them. But that is not even the main point. There are other important advantages:
Clarifies Intent
Using Optional
clearly expresses that the variable is, well, optional. Any reader of your code or consumer of your API will be beaten over the head with the fact that there might be nothing there and that a check is necessary before accessing the value.
Removes Uncertainty
Without Optional
the meaning of a null
occurrence is unclear. It could be a legal representation of a state (see Map.get
) or an implementation error like a missing or failed initialization.
This changes dramatically with the persistent use of Optional
. Here, already the occurrence of null
signifies the presence of a bug. (Because if the value were allowed to be missing, an Optional
would have been used.) This makes debugging a null pointer exception much easier as the question of the meaning of this null
is already answered.
More Null Checks
Now that nothing can be null
anymore, this can be enforced everywhere. Whether with annotations, assertions or plain checks, you never have to think about whether this argument or that return type can be null. It can't!
Disadvantages
Of course, there is no silver bullet...
Performance
Wrapping values (especially primitives) into an extra instance can degrade performance. In tight loops this might become noticeable or even worse.
Note that the compiler might be able to circumvent the extra reference for short lived lifetimes of Optional
s. In Java 10 value types might further reduce or remove the penalty.
Serialization
Optional
is not serializable but a workaround is not overly complicated.
Invariance
Due to the invariance of generic types in Java, certain operations become cumbersome when the actual value type is pushed into a generic type argument. An example is given here (see "Parametric polymorphism").
Solution 3 - Java
Personally, I prefer to use IntelliJ's Code Inspection Tool to use @NotNull
and @Nullable
checks as these are largely compile time (can have some runtime checks) This has lower overhead in terms of code readability and runtime performance. It is not as rigorous as using Optional, however this lack of rigour should be backed by decent unit tests.
public @Nullable Foo findFoo(@NotNull String id);
public @NotNull Foo doSomething(@NotNull String id, @Nullable Bar barOptional);
public class Book {
private List<Pages> pages;
private @Nullable Index index;
}
List<@Nullable Foo> list = ..
This works with Java 5 and no need to wrap and unwrap values. (or create wrapper objects)
Solution 4 - Java
I think the Guava Optional and their wiki page puts it quite well:
> Besides the increase in readability that comes from giving null a name, the biggest advantage of Optional is its idiot-proof-ness. It forces you to actively think about the absent case if you want your program to compile at all, since you have to actively unwrap the Optional and address that case. Null makes it disturbingly easy to simply forget things, and though FindBugs helps, we don't think it addresses the issue nearly as well.
> This is especially relevant when you're returning values that may or may not be "present." You (and others) are far more likely to forget that other.method(a, b) could return a null value than you're likely to forget that a could be null when you're implementing other.method. Returning Optional makes it impossible for callers to forget that case, since they have to unwrap the object themselves for their code to compile. -- (Source: Guava Wiki - Using and Avoiding null - What's the point?)
Optional
adds some overhead, but I think its clear advantage is to make it explicit
that an object might be absent and it enforces that programmers handle the situation. It prevents that someone forgets the beloved != null
check.
Taking the example of 2, I think it is far more explicit code to write:
if(soundcard.isPresent()){
System.out.println(soundcard.get());
}
than
if(soundcard != null){
System.out.println(soundcard);
}
For me, the Optional
better captures the fact that there is no soundcard present.
My 2¢ about your points:
public Optional<Foo> findFoo(String id);
- I am not sure about this. Maybe I would return aResult<Foo>
which might be empty or contain aFoo
. It is a similar concept, but not really anOptional
.public Foo doSomething(String id, Optional<Bar> barOptional);
- I would prefer @Nullable and a findbugs check, as in Peter Lawrey's answer - see also this discussion.- Your book example - I am not sure if I would use the Optional internally, that might depend on the complexity. For the "API" of a book, I would use an
Optional<Index> getIndex()
to explicitly indicate that the book might not have an index. - I would not use it in collections, rather not allowing null values in collections
In general, I would try to minimize passing around null
s. (Once burnt...)
I think it is worth to find the appropriate abstractions and indicate to the fellow programmers what a certain return value actually represents.
Solution 5 - Java
From Oracle tutorial:
> The purpose of Optional is not to replace every single null reference in your codebase but rather to help design better APIs in which—just by reading the signature of a method—users can tell whether to expect an optional value. In addition, Optional forces you to actively unwrap an Optional to deal with the absence of a value; as a result, you protect your code against unintended null pointer exceptions.
Solution 6 - Java
In java, just don't use them unless you are addicted to functional programming.
They have no place as method arguments (I promess someone one day will pass you a null optional, not just an optional that is empty).
They make sense for return values but they invite the client class to keep on stretching the behavior-building chain.
FP and chains have little place in an imperative language like java because it makes it very hard to debug, not just to read. When you step to the line, you can't know the state nor intent of the program; you have to step into to figure it out (into code that often isn't yours and many stack frames deep despite step filters) and you have to add lots of breakpoints down to make sure it can stop in the code/lambda you added, instead of simply walking the if/else/call trivial lines.
If you want functional programming, pick something else than java and hope you have the tools for debugging that.
Solution 7 - Java
> 1 - As a public method return type when the method could return null:
Here is a good article that shows usefulness of usecase #1. There this code
...
if (user != null) {
Address address = user.getAddress();
if (address != null) {
Country country = address.getCountry();
if (country != null) {
String isocode = country.getIsocode();
isocode = isocode.toUpperCase();
}
}
}
...
is transformed to this
String result = Optional.ofNullable(user)
.flatMap(User::getAddress)
.flatMap(Address::getCountry)
.map(Country::getIsocode)
.orElse("default");
by using Optional as a return value of respective getter methods.
Solution 8 - Java
Here is an interesting usage (I believe) for... Tests.
I intend to heavily test one of my projects and I therefore build assertions; only there are things I have to verify and others I don't.
I therefore build things to assert and use an assert to verify them, like this:
public final class NodeDescriptor<V>
{
private final Optional<String> label;
private final List<NodeDescriptor<V>> children;
private NodeDescriptor(final Builder<V> builder)
{
label = Optional.fromNullable(builder.label);
final ImmutableList.Builder<NodeDescriptor<V>> listBuilder
= ImmutableList.builder();
for (final Builder<V> element: builder.children)
listBuilder.add(element.build());
children = listBuilder.build();
}
public static <E> Builder<E> newBuilder()
{
return new Builder<E>();
}
public void verify(@Nonnull final Node<V> node)
{
final NodeAssert<V> nodeAssert = new NodeAssert<V>(node);
nodeAssert.hasLabel(label);
}
public static final class Builder<V>
{
private String label;
private final List<Builder<V>> children = Lists.newArrayList();
private Builder()
{
}
public Builder<V> withLabel(@Nonnull final String label)
{
this.label = Preconditions.checkNotNull(label);
return this;
}
public Builder<V> withChildNode(@Nonnull final Builder<V> child)
{
Preconditions.checkNotNull(child);
children.add(child);
return this;
}
public NodeDescriptor<V> build()
{
return new NodeDescriptor<V>(this);
}
}
}
In the NodeAssert class, I do this:
public final class NodeAssert<V>
extends AbstractAssert<NodeAssert<V>, Node<V>>
{
NodeAssert(final Node<V> actual)
{
super(Preconditions.checkNotNull(actual), NodeAssert.class);
}
private NodeAssert<V> hasLabel(final String label)
{
final String thisLabel = actual.getLabel();
assertThat(thisLabel).overridingErrorMessage(
"node's label is null! I didn't expect it to be"
).isNotNull();
assertThat(thisLabel).overridingErrorMessage(
"node's label is not what was expected!\n"
+ "Expected: '%s'\nActual : '%s'\n", label, thisLabel
).isEqualTo(label);
return this;
}
NodeAssert<V> hasLabel(@Nonnull final Optional<String> label)
{
return label.isPresent() ? hasLabel(label.get()) : this;
}
}
Which means the assert really only triggers if I want to check the label!
Solution 9 - Java
Optional
class lets you avoid to use null
and provide a better alternative:
-
This encourages the developer to make checks for presence in order to avoid uncaught
NullPointerException
's. -
API becomes better documented because it's possible to see, where to expect the values which can be absent.
Optional
provides convenient API for further work with the object:
isPresent()
; get()
; orElse()
; orElseGet()
; orElseThrow()
; map()
; filter()
; flatmap()
.
In addition, many frameworks actively use this data type and return it from their API.
Solution 10 - Java
An Optional
has similar semantics to an unmodifiable instance of the Iterator design pattern:
- it might or might not refer to an object (as given by
isPresent()
) - it can be dereferenced (using
get()
) if it does refer to an object - but it can not be advanced to the next position in the sequence (it has no
next()
method).
Therefore consider returning or passing an Optional
in contexts where you might previously have considered using a Java Iterator
.
Solution 11 - Java
Here are some of the methods that you can perform on an instance of Optional<T>
:
map
flatMap
orElse
orElseThrow
ifPresentOrElse
get
Here are all the methods that you can perform on null
:
- (there are none)
This is really an apples to oranges comparison: Optional<T>
is an actual instance of an object (unless it is null
… but that would probably be a bug) while null
is an aborted object. All you can do with null
is check whether it is in fact null
, or not. So if you like to use methods on objects, Optional<T>
is for you; if you like to branch on special literals, null
is for you.
null
does not compose. You simply can’t compose a value which you can only branch on. But Optional<T>
does compose.
You can, for instance, make arbitrary long chains of “apply this function if non-empty” by using map
. Or you can effectively make an imperative block of code which consumes the optional if it is non-empty by using ifPresent
. Or you can make an “if/else” by using ifPresentOrElse
, which consumes the non-empty optional if it is non-empty or else executes some other code.
…And it is at this point that we run into the true limitations of the language in my opinion: for very imperative code you have to wrap them in lambdas and pass them to methods:
opt.ifPresentOrElse(
string -> { // if present...
// ...
}, () -> { // or else...
// ...
}
);
That might not be good enough for some people, style-wise.
It would be more seamless if Optional<T>
was an algebraic data type that we could pattern match on (this is obviously pseudo-code:
match (opt) {
Present(str) => {
// ...
}
Empty =>{
// ...
}
}
But anyway, in summary: Optional<T>
is a pretty robust empty-or-present object. null
is just a sentinel value.
Subjectively disregarded reasons
There seems to be a few people who effectively argue that efficiency should determine whether one should use Optional<T>
or branch on the null
sentinel value. That seems a bit like making hard and fast rules on when to make objects rather than primitives in the general case. I think it’s a bit ridiculous to use that as the starting point for this discussion when you’re already working in a language where it’s idiomatic to make objects left-and-right, top to bottom, all the time (in my opinion).
Solution 12 - Java
I do not think that Optional is a general substitute for methods that potentially return null values.
The basic idea is: The absence of a value does not mean that it potentially is available in the future. It's a difference between findById(-1) and findById(67).
The main information of Optionals for the caller is that he may not count on the value given but it may be available at some time. Maybe it will disappear again and comes back later one more time. It's like an on/off switch. You have the "option" to switch the light on or off. But you have no option if you do not have a light to switch on.
So I find it too messy to introduce Optionals everywhere where previously null was potentially returned. I will still use null, but only in restricted areas like the root of a tree, lazy initialization and explicit find-methods.
Solution 13 - Java
Seems Optional
is only useful if the type T in Optional is a primitive type like int
, long
, char
, etc. For "real" classes, it does not make sense to me as you can use a null
value anyway.
I think it was taken from here (or from another similar language concept).
In C# this Nullable<T>
was introduced long ago to wrap value types.
Solution 14 - Java
Java SE 8 introduces a new class called java.util.Optional
You can create an empty Optional or Optional with null value.
Optional<String> emptyOptional = Optional.empty();
And here is an Optional with a non-null value:
String valueString = new String("TEST");
Optional<String> optinalValueString = Optional.of(valueString );
Do Something If a Value Is Present
Now that you have an Optional object, you can access the methods available to explicitly deal with the presence or absence of values. Instead of having to remember to do a null check, as follows:
String nullString = null;
if (nullString != null) {
System.out.println(nullString);
}
You can use the ifPresent() method, as follows:
Optional<String> optinalString= null;
optinalString.ifPresent(System.out::println);
package optinalTest;
import java.util.Optional;
public class OptionalTest {
public Optional<String> getOptionalNullString() {
return null;
// return Optional.of("TESt");
}
public static void main(String[] args) {
OptionalTest optionalTest = new OptionalTest();
Optional<Optional<String>> optionalNullString = Optional.ofNullable(optionalTest.getOptionalNullString());
if (optionalNullString.isPresent()) {
System.out.println(optionalNullString.get());
}
}
}