Java 8: Obliged to do the Optional ... or is it optional?
Siegfried Steiner
Siegfried Steiner
9 min read

Categories

Tags

There is some controversy going on around the Java community regarding the Optional type introduced by Java 8. It has been around before1 though now it’s official.

Something I hear during daily business lately here and there:

… never return null, return an Optional object …” +++ “… you won’t throw an Exception, you must return an Optional instance …” +++ “NullPointerExceptions belong to the past when you use the Optional type …

Am I obliged to use Java 8’s Optional type?

The motive which caused me to contribute some thoughts on the discussion was the design of a service

Some example

Given some kind of service which returns a list of items with attributes such as an id, a name, a description and whatsoever. The id unambiguously identifying a single unique item. The ids are assigned by the service upon creation of an item. The service provides you methods such as getAllItems() returning a collection with item objects (having an id, a name, a description and whatsoever).

Now the code fragment in question was the method contract for retrieving a single item by an unambiguous id. Amongst others you could consider the below three options on how to design the required functionality:

  • Option 1: Return null if there is no item with such an id:
Item getItem( String id );
  • Option 2: Return an Optional to be forced to take care of the presence or the absence of the item:
Optional<Item> getItem( String id );
  • Option 3: Cause an exceptional situation in case there is no item for the given id:
Item getItem( String id ) throws NoSuchItemException;

Whilst having some coding session we came across the options above, in the group there was someone’s definite statement to use the second option Optional<Item> getItem( String id ); as this is the right one whilst Item getItem( String id ) throws NoSuchItemException; is simply not the way to do it anymore.

Usually I feel uncomfortable with definite statements such as the one above; it’s just a statement without a profound reasoning, there is some smell on it … so I decided to do some research and activate my brain. When searching the web for “java 8 Optional”, amongst the first results are articles such as “Tired of Null Pointer Exceptions? Consider Using Java SE 8’s Optional!” or “Java 8 Optional: How to Use it”.

Gotten some input and doing some thinking I believe it is simply bad style to use option 2 Optional<Item> getItem( String id ); in the given example above. My favorite approach for the given case is option 3. Item getItem( String id ) throws NoSuchItemException;. I’ll tell you why:

Reasoning

Let’s take a look at at the example and the semantics behind the desired retrieval operation: I pass an id to the service to retrieve the according item. I have an id which I did not make up in my mind. I got the id from somewhere; either I provided it to the service whilst creating an item and the service accepted it without objection. Or upon an according request from my part to the service, it provided me with a list of items; each providing its id attribute.

Given this, I actually expect to get an item for the provided id and given that nothing unexpectedly happen to that item. So the ordinary (intended) execution path of my business logic expects an item in order to proceed. Not getting an item would force me to leave the ordinary execution path of my business logic and handle this unusual (unexpected or exceptional) situation. Let’s examine the options introduced before:

Option 1

Item getItem( String id );

I might expect an item as the method’s signature does not draw my attention to the exceptional situation (varying from the ordinary one) of null being returned when there is no such item. I might just continue the ordinary execution path even though I got a null reference. And voilà, there is that NullPointerException when I apply method calls on that non-existing item. You could do a null test before continuing with the ordinary execution path, though then you mix up the exceptional execution path with the ordinary one.

You may run unwarned into a NullPointerException. The ordinary and the exceptional execution paths get mixed up: The code gets more complex and its readability (and maintainability) becomes poor and your concerns are not separated2 any more.

Looks to me Option 1 is bad …

Option 2

Optional<Item> getItem( String id );

Now the Optional draws your attention to the possibility of the absence of an item. You switch on your brain and feel you have to take some precautions in case of the absence of an item. You might test for an item’s presence and leave the ordinary execution path in case of its absence and enter an exceptional execution path to gracefully cope with this situation. This looks much better than returning null.

The drawback here is similar to the null test of Option 1: As you test for the presence of an item before continuing with the ordinary execution path, you mix up the exceptional execution path with the ordinary one.

You do not run unwarned into a NullPointerException anymore. The ordinary and the exceptional execution paths still get mixed up: The code gets more complex and its readability (and maintainability) becomes poor and your concerns are still not really separated2.

You can argue that the Optional allows you to separate your concerns, though Java already provides stronger means to express and separate exceptional situations.

Regarding the method signature, it feels that the presence or the absence of an item are equally valid options for that method call, although we are pretty sure to expect an item for our ordinary execution path.

Looks to me Option 2 has a smell …

Option 3

Item getItem( String id ) throws NoSuchItemException;

In case there is no item for the provided id a NoSuchItemExceptionis thrown. In such a case you leave the ordinary execution path and enter the exceptional execution path without having to bother with the exceptional situation in your ordinary execution path. The exceptional execution path is cleanly separated from your ordinary execution part (by a catch block), enhancing readability and not mixing up your concerns. This is a quite strong expressiveness Java offers us.

Your ordinary execution path can concentrate on its sunny day business logic. The exceptional execution path is cleanly separated2 from the ordinary execution path (by a catch block) improving readability and maintainability. And finally you are forced to take care of the exceptional execution path without accidentally running into a NullPointerException.

Option 3 feels like a sound solution to me!

It depends!

When I had to make some definite statement, I’d say: It depends … a dogmatic right or wrong does not lead to better software - switch on your brains … are you in a service or a data-structure, is it really optional or exceptional what you try to figure out?

I decided to distinguish between the ordinary execution path and an exceptional execution path of my business logic as well as between services and data-structures:

Ordinary execution path

That’s it what you actually want to accomplish with your business logic. As of my opinion, everything which does not belong to your ordinary execution path does not belong inside an Optional instance.

Exceptional execution path

That’s what might come into your way trying to accomplish the ordinary execution path of your business logic. Once again, everything which does belong to your exceptional execution path does not belong inside an Optional instance.

Service method

Being the service a part of my business logic, I use the Optional type when the presence or the absence of an item really is optional from the business logic’s point of view. If you expect an item as of the example before, I solely expect an item instance and everything else is exceptional (as of Option 3 above). Given you want to retrieve an optional comment for an item, the method provided by the service could look as follows:

Optional<String> getComment( String itemId );

At a first glance I would be fine with that. Though from a software designer’s point of view this has a smell as well:

Data-structure attribute

Instead of adding a method as such above, I definitely prefer to have an optional comment attribute in the item type. So make the comment attribute in your item be Optional<String> getComment();! The id attribute is definitely not optional, here precautions (assertions) should be taken that id never can be null. So it obviously makes sense to distinguish between a service and a data-structure.

“Just my 5 cents …”

Some further notes

Since Java 8 there are lambda expressions (aka closures). The Optional provides an ifPresent(Consumer<? super T> consumer) method which you can feed with a lambda invoked only in case the Optional wraps something else than null. This eases the life of the developer’s daily work. Also by providing a default value in case the Optional contains just a null reference via the orElse(T other) method makes life easier.

Facilitate the power of functional programming with the Optional class.

Interesting to consider is that the Optional is not Serializable making it useless whenever you propagate a value by serialization throughout JVM borders. This happens quite often when using REST or SOAP based communication. Here it is up to the underlying framework to take care of proper handling.

Having done some research before writing this article I stumbled over some inspiring texts:

… An immutable object that may contain a non-null reference to another object. Each instance of this type either contains a non-null reference, or contains nothing (in which case we say that the reference is “absent”); it is never said to “contain null” …”1

… design principle for separating a computer program into distinct sections, such that each section addresses a separate concern …2

… You should use Optionals in your data model: to leverage the type system to clearly differentiate the values that can be missing (the car in the Person class and the insurance in the Car class in my example) from the ones that must be there (the name of the insurance company). In this way you know, through the type system, that a person without a car is acceptable in your data model while an insurance company without a name isn’t …3

… Optional is an attempt to reduce the number of null pointer exceptions in Java systems, by adding the possibility to build more expressive APIs that account for the possibility that sometimes return values are missing …4

… String version = computer.getSoundcard().getUSB().getVersion(); … A common (bad) practice is to return the null reference to indicate the absence of a sound card. Unfortunately, this means the call to getUSB() will try to return the USB port of a null reference, which will result in a NullPointerException at runtime and stop your program from running further …5