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?
So, to overcome this, Java 8 has introduced a new class Optional in java. util package. It can help in writing a neat code without using too many null checks. By using Optional, we can specify alternate values to return or alternate code to run.
Optional of() method in Java with examples Parameters: This method accepts value as parameter of type T to create an Optional instance with this value. Return value: This method returns an instance of this Optional class with the specified value of the specified type.
In Java, the Optional object is a container object that may or may not contain a value. We can replace the multiple null checks using the Optional object's isPresent method. The empty method of the Optional method is used to get the empty instance of the Optional class. The returned object doesn't have any value.
In a nutshell, the Optional class includes methods to explicitly deal with the cases where a value is present or absent. However, the advantage compared to null references is that the Optional class forces you to think about the case when the value is not present.
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.
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).
I wrote an entire blog post about using Optional
but it basically comes down to this:
Optional
instead of null
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. ;)
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:
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.
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.
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!
Of course, there is no silver bullet...
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.
Optional
is not serializable but a workaround is not overly complicated.
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").
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With