The Optional class introduced with Java 8 has been one of the most controversial features introduced by that version of the language. Although I like more things about this new Java class than I dislike, there are a few things to consider when employing it as a return
type in Java methods. I discuss some of them in this post, but don't discuss the controversy about whether Optional
should be limited to use as a return type. I also assume that Optional
is only used as a return type when it's expected that there are cases where that method should have no value to return. Finally, these observations apply to other types and to direct use of null
in Java as well, but Optional
emphasizes and concretely illustrates these observations.
Single Versus Multiple Returns
There has been a debate ("religious war") in the general software development community and in the Java development community specifically for some time about whether methods should be written to only return
once (not counting throwing exceptions in this discussion). On one side, Yegor Bugayenko argues that "many return statements are a bad idea in OOP", Tom Dalling argues that "having one exit point (return) from a function is a good thing", and many have argued that multiple return
statements often indicate need of that method to be refactored. On the other side, Bruce Eckel argues that multiple return
statements can make the code "clearer", Taylor Gautier argues that the "maxim" "A method should have one and only one exit point" "couldn't be more wrong", Peter Ritchie argues that strict adherence to single-exit can lead to "less readable" code today in "in Object-Oriented languages", and Mark Levison outlines "some reasons I dislike the single exit argument."
In the post "Multiple Return Statements," Nicolai Parlog writes about the history of and considerations to be made related to the idea of a method returning only once. He includes a section "Situations For Multiple Returns Statements" in which he outlines "several kinds of situations in which a method can profit from multiple return statements." My best guess is that many developers feel the way I do, which is that "it depends" when deciding whether a particular method should have only one return
statement or should have more than one return
statement.
As I've begun using Java 8's Optional more frequently for my methods' return types, I'm finding that the use of Optional as a return type is another consideration to be made when deciding whether to return once or multiple times from a method.
When declaring that a Java method returns an Optional
it's important to fully understand that this does not preclude the developer who writes this method from returning null
. The returned Optional
is a reference type and, like any reference type, can be null
. It is paramount that a developer writing a method that returns Optional
should NEVER have that method return null
[Optional.empty() should generally be returned instead]. I'm going to reiterate this point with two quotations:
- Highlighted sentence from Item #55 in Effective Java, Third Edition: "Never return a null value from an
Optional
-returning method." - Stuart Marks's #1 rule for using
Optional
, "Never, ever, use null for an Optional variable or return value."
One of the arguments against multiple return statements in a method is that it makes it more difficult to recognize what is returned in each case (to find all the different possible return scenarios). The use of Optional
as a return type is a specific example illustrating this. One would want to make sure that one's method does not return null
in some cases and an Optional
instance in other cases. The compiler certainly won't care which is returned in each case.
One approach for dealing with this is to only return from a method once and then the developer writing the code and the developer reviewing the code can easily ensure that null
is not returned. These developers would need to only look for an Optional.of(T) call, an Optional.ofNullable(T) call, or an Optional.empty() call.
Work with Local Variable of Underlying Data Type in Method
This approach at avoiding the accidental return of null
instead of an empty Optional
works best when the Optional
is instantiated at the point of return. In other words, I have found it better to work with the type wrapped by the Optional
throughout the method and then place it in the Optional
at the last possible moment. The next code listing provides ridiculously trivial examples of this.
Examples of Declaring Local Variable that is Ultimately Returned as Optional
/** * Provides the middle name if it exists. * * @return Middle name if it exists or empty if it doesn't exist. */ public Optional<String> determineMiddleName1() { String middleName; // Do whatever logic is necessary return Optional.ofNullable(middleName); } /** * Provides the middle name if it exists. * * @return Middle name if it exists or empty if it doesn't exist. */ public Optional<String> determineMiddleName2() { Optional<String> middleName; // Do whatever logic is necessary return middleName; }
In the above code, the determineMiddleName1()
method works with the local variable of the underlying type. This is typically easier to set/populate than Optional
and the use of Optional.isNullable()
at the ends ensures that even null
middleName will be returned as an "empty" Optional
instead of null
.
The determineMiddleName2()
method in the above code declares its local variable that will ultimately be returned as an Optional<String>
and then returns that reference at the end of the method.
Avoid "Default" Initialization of Local Variable
As method determineMiddleName2()
is written above, the compiler will help ensure that the local variable "middleName" is set to something (even if that "something" is null
), but had the developer chosen to initialize that "middleName" variable to null
to begin with, the compiler would have no issue with it. If the local variable needs to be initialized for some reason, it would be better to initialize it to Optional.empty()
instead of null
. Had the developer chosen to initialize that variable with Optional.empty()
, it's still possible for that second example to "reset" the local variable to null
later in the method.
This discussion leads me to three opinionated observations regarding use of Optional
as a method return type in Java.
- The influence of single
return
or multiplereturn
s on the possibility of returningnull
accidentally instead of an "empty" or other non-null
Optional
reference should be considered when deciding on whether a single return or multiple returns makes most sense. - It will often be easier to ensure return of an
Optional
reference rather than return of anull
by working on the the underlying type throughout the method and only instantiating the returnedOptional
at the latest moment (typically at itsreturn
). - A local variable of type
Optional
that is ultimately to be returned from a method should NEVER be initially assigned tonull
even if it is "known" that it will be re-set appropriately. It may be best to not define it at all so that the compiler will ensure it needs to be set in each "branch" of the code flow. At the very least, if it is to be initialized, that local variable of typeOptional
should be initialized toOptional.empty()
instead of tonull
.
These observations can be combined. For example, when it's determined that a method should have multiple returns (such as to implement guard clauses), one could return appropriate non-null
Optional
references at the point of each return and not initialize the local variable until needed (after getting through the guards). This is illustrated with the next ridiculously contrived example.
Example of Avoid Return of Null with Multiple Return Statements
public Optional<String> getGuardedData(final String input) { if (input == null) { return Optional.empty(); } String data; // Do whatever logic is necessary return Optional.ofNullable(data); }
I have found the Optional
class, when used properly as a method return type, can make the client's code more readable because of its greater fluency. However, to achieve its maximum value, Optional
must be applied with discipline such that clients of the code can expect the returned Optional
to never be null
. This post has looked at a few considerations that can be made to help ensure that null
is never returned from a method that advertises itself as returning Optional
. Without trust that the method will never return null
, use of Optional
as a return type only makes things worse because it forces the client to first check for a non-null
Optional
before invoking one of the methods on that Optional
. That makes the calling code less fluent.
3 comments:
Newline-braces in Java code removes any credability immediately.
@SG You mean credibility? ;)
@SG - your decision to comment on something as trivial as newline-braces instead of any considered discussion of the article removes any credibility that you have!
Post a Comment