Here are some things you should know about using
Optionals effectively. It is a useful tool that may or may not be appropriate for your use case. I hope this article will help you avoid making common mistakes with
Optional operations are not lazy
Optionals are not
Streams. They are not lazy by nature. If you’re using Java 9 then you can use
stream() method to transform eager
Optional to a lazy
Stream. In Java 8 this requires a custom utility method.
When you use
Optional::orElse method you should remember that it does not behave the same way as
if-else block. Instructions inside
else branch of
if-else block run only if certain condition is not met (lazily). Any expression you put inside
orElse() is always evaluated (eagerly). It can be as harmless as creating a
but it can also be a hidden performance killer
Code above works fine if a resource is absent. However if the resource is present then the expression inside
orElse() is evaluated eagerly anyway. Hence each call to
getResource() creates a new resource. This operation can be expensive for all we know.
Fix is very simple. Substitute
orElseGet(). This will delay the evaluation till it is required.
Supplier as a parameter so you can pass lambdas to it.
As you can see
orElse() is more suited for assigning literal values than flow control.
If instead of supplying a default value or running an action you would prefer to throw an exception when
Optional is empty then you can use
Java 8 does not give us a great way to control the flow when you are chaining
Optionals. Not everything is intuitive and you have to know what you are doing. Most of the time
if-else block or
Stream is better and cleaner choice than Java 8
map().orElseGet() solution is similar construct to
if-else block. Code inside
map() corresponds to
if branch and code inside
orElseGet() corresponds to
else branch. Sometimes you have no need for the
else branch. You can use
ifPresent() in that case.
Consumer as a parameter.
Java 9 brings some long awaited changes in
Optional. My favorite by far is
stream() method but there are also other goodies like
Optional is not an excuse for no input validation
Optionals does not excuse you from thinking about bad input. You should always validate your input. Return default value or fast-fail if you get bad data. If all you do all over your application is swallowing
nulls then you will never get an
Exception. Consequently you allow bad input to travel through your code and possibly produce some unexpected output.
If you are lucky nothing happens or you call a method using that travelling
null reference and you get
NullPointerException. Likewise, if you call
Optional.empty() you will get
NoSuchElementException. Also your tests might detect the bug before code goes to production.
If you are unlucky, no exceptions will be thrown, your tests will not detect the bug and your clients will get bad output.
Forget about get()
Have a look at the two quotes below.
I call it my billion-dollar mistake
– Tony Hoare, Inventor of null reference
We should have never called it get(). We should have called it getOrThrowSomethingHorribleIfTheThingIsEmpty()
– Brian Goetz, Java Language Architect
if isPresent() then get() construct in reality is not very different from good old
null checks. Not only exception is thrown if you call
get() on an empty
Optional but also forgetting to guard
get() is just as easy as forgetting to guard
null. There are alternative ways to use
Optional that will produce better quality code.
Access object inside Optional
get() is not necessary in most cases. If all you want to do is retrieve a property value of an object that is boxed inside the
Optional you can do the following
map() substitutes the value inside the
Optional with the result of the function call. What you need to understand here is that
orElse() method is the one that extracts the value from the
Optional. In case there was no result default value is returned.
If you need the boxed object then you can use
Supplier . In the example below null object pattern can be used to take the burden of handling
null away from the client.
Use Optional as method return type
This is what primarily
Optionals were created for. If you find yourself using
Optional type for a field, parameter or in collection context then you should have a second look at your code.
Optionals were introduced to represent no result in methods that are exposed to the outside world.
Optionals can also be used whenever you need notion of result and a lack of it. Do not get carried away and put an
It is perfectly fine to use
null for the fields you are using internally in the class. However you do not want to pass that
null value to the client of your API. How is the client supposed to know what to do with it and what does
null return value mean ? On the other hand if your client receives an
Optional then there are only two possibilities. Result is present or result is empty.
Optional as an input parameter might be a sign that you are doing more than you should inside a function. Treat such code occurrence as a warning sign. Verify that you are not breaking single responsibility principle inside that code. Consider splitting the method or refactoring the code some other way.
Optional in a collection or as a field for the objects that are inside that collection might not be a good idea.
Optional consumes 4 x the memory and probably more CPU than a bare reference. If collection contains large number of elements then using
Optionals instead of references can result in reduced performance.
No complex Optionals please
Immediately stop if you find yourself thinking about monster-like
orElseGet() inside another
orElseGet(). If you are using Java 9 then
or() method should be of use. In Java 8 you should probably be using a
Stream or a bunch of some good ol’
if-else blocks with
Suppliers you have the less readable
Stream code gives you more flexibility but it is not clear at first sight what it is doing.
Optionalwith caution. Do not forget about the eagerness of
Optionalsare great as method return types and can potentially cause problems if used in fields, parameters and collections.
Optional::getshould be avoided. This method is on a good path to deprecation.
- If you’re using Java 9 you should definitely incorporate
ifPresentOrElse()methods to your project for cleaner code.
- Keep your
Optionalsimple. Do not force
Optionalto do something it was not designed for. Check if using short if,
Streamisn’t a better choice after all.