Rule
Do not useOptional
for constructor or method parameters.
Rule
Do not declare instance variables asOptional
.
Suggestion
UseOptional
for return types that can have no result.
Optional
is intended to be a limited way for library methods to represent "no result" return types. It is not intended to be used as an all-purpose way to safely handle null
or to be a complete shift away from using null
.1
This is also supported by what we've seen with our usage of Optional
. Used excessively, it feels cumbersome and awkward since objects end up being converted to or from Optional
just to satisfy a type signature.
Within a class, you should use null
to represent optional data. That data can be returned as an Optional
to external callers.
WARNING
Single parameter methods returningOptional
should either not expectnull
as an input or mapnull -> Optional.empty()
.
Otherwise, developers using such a method may run into unexpected behavior. For more on this, please see the related warning below.
Rule
UseOptional.of
overOptional.ofNullable
if your argument cannot benull
.
The two are the same from a code perspective, but differ when it comes to readability. Optional.of
lets future developers know that the argument will not be null without them needing to read how that argument is computed.
Rule
Optional.get
should not be used unless you know it is safe. Instead, use a method such asorElse
orifPresent
.2
Suggestion
UseOptional.map
orOptional.flatMap
to map anOptional
value before unboxing it. This is in contrast to unboxing anOptional
and then mapping it, since that requires explicitly dealing withnull
.
// SUGGESTED
Optional<Business> business = getBusiness();
Business parentBusiness = business.map(Business::getParentBusiness).orElse(null);
// ALTERNATIVE
Business business = getBusiness().orElse(null);
Business parentBusiness = null;
if (business != null) {
parentBusiness = business.getParentBusiness();
}
WARNING
The functions passed in toOptional.map
orOptional.flatMap
should trivially handlenull
as an input.
To be specific, "trivially handle" means one of the following:
- The function is never expected to receive a
null
input. - For
Optional.map
, the function mapsnull -> null
.3 - For
Optional.flatMap
, the function mapsnull -> Optional.empty()
.
The underlying reason for this is that Optional
cannot contain null
. This causes functions that don't follow one of the above points to behave in unexpected ways when it comes to identities4 or composition/chaining.5
Code Smell
Complex return types involvingOptional
, such as usingOptional
as a type parameter, will likely obfuscate the meaning of your code. Additionally, that return type is not likely to be friendly to or useful for the caller.6
- A return type of
Optional<List<T>>
can likely be replaced with justList<T>
, returning an empty list when you have no results. - A return type of
List<Optional<T>>
implies that the caller will care about elements that are not present. This is often not the case.
Footnotes
-
http://blog.joda.org/2015/08/java-se-8-optional-pragmatic-approach.html ↩
-
https://stackoverflow.com/questions/26327957/should-java-8-getters-return-optional-type/26328555#26328555 ↩
-
Additionally, the function cannot be composed of any functions that do not handle
null
in this way. ↩ -
Optional.flatMap
does not satisfy the left-identity monad law for functions that "do stuff" withnull
. ↩ -
Optional.map
does not satisfy functor composition for functions that "do stuff" withnull
. ↩ -
http://mail.openjdk.java.net/pipermail/lambda-libs-spec-experts/2012-September/000014.html ↩