Over a million developers have joined DZone.

Using Java 8's 'Optional' is Optional

Give Optional to code you trust, accept it from code that does not trust your code, but do not request it! Trust yourself!

· Java Zone

What every Java engineer should know about microservices: Reactive Microservices Architecture.  Brought to you in partnership with Lightbend.

After the article of last week “Optional in collections” today I can’t help but talking a bit more about the same beast in a bit more detail.

The class Optional was originally introduced by Google Guava and later included in the Java 8 package simply as a wrapper that wraps an optional object. The wrapped object is optional in the sense that it is either there, or there is no object in the wrapping, in which case it is empty. There is not too much magic there.  After all null is null and not an object. An object is never null. Only a reference to an object can be null.

These are nuances, fine details; but important fine details. After all, these fine details are those that required the introduction of Optional. Average Java coders do not see the importance of such tiny details. They think that Optional is just as good as a variable to the wrapped object itself assuming that the variable can also be null. At some level they are right. At their own level.

That level says that the good code works, can be understood and that is it. Most of enterprise legacy code that run banks, insurance companies, pace makers and weapons were made on this level. You can not do anything about it, just hope that you have luck and a software bug will not select your house, bank account or body (in the case of medical device). What you can do is to understand the issue and do your part to slowly improve the situation. It will take a few generations, unless we all are wiped out before that.

“Working” and “understandable” are the very basic requirements for software. We used to say that if the software runs then it was okay, and for maintenance it was enough if there were two people who could understand the code: the coder who created it and God, who created the coder. Fortunately there are also levels higher. (I mean above the coder. Not above God.)

“Code working” and “easy (not so hard) to understand” are the next level. This is important in case you have to debug the code and need to identify the root cause of some malfunction. “Code working” and “easy to modify” are again new steps up the ladder. I had seen code that I could easily understand. The code was running. But the dependencies between the different modules were so complex like a macrame or a traditional Italian spagetti. Wherever I wanted to change something to fix a bug here, there were a few other places where the program started to fail. Easy to modify: that code was not.

The next level is “code working”, “easy to modify” and “hard to create bad modifications”. This means that the code provides style and internal data structures and APIs that the maintaining person will follow to some level and will createa  working modified codebase that still works, is easy to understand and easy to modify. This is the point where we get to the point of Optional.

When a method returns Optional, it says that it may return something or just nothing. Optional<Integer> may return an Integer but it may just return an empty Optional, which means: there was no Integer that I could return. Why is it any better than returning an Integer that may optionally be null?

Optional Method Return Value

The answer is that in case of returned Optional<Integer> you can not

integer = methodReturningIntegerOrNull();
otherInteger = integer +1;

that causes NPE. Why would you do that? Because you forget to check, and the JavaDoc mentions the possibility somewhere at the end of the description that is not visible in the mouse over window when you code. In case of Optional<Integer> you are forced to

optionalInteger = methodReturningOptionalInteger();
if( optionalInteger.isPresent() ){
  otherInteger = optionalInteger.get() +1;
  }

Still there is a small chance that you will write:

optionalInteger = methodReturningOptionalInteger();
otherInteger = optionalInteger.get() +1;

but in that case you deserve what you get.

Optional helps you to create more code and less documentation. It gives a semantic to pass on some optional value in a way that is harder to neglect than a nullable value. It says: I do not trust you handling null properly, therefore I give you a wrapped object so you have to handle optionality explicitly.

If you consider that you can easily answer the questions

  • Requiring Optional<Something> as a method argument
  • Having a private field optional.

are good ideas.

Optional method argument

There are pros and cons. When the argument says

countFrom(Optional<Date> from, Date to);

it is clear that the from value may be missing and there should be some special default semantics when an absent value is passed. On the other hand the caller may pass null to get the special behavior. It is less likely that the caller will pass null just by mistake neglecting the optionality. Even if the argument is Optional the argument actually passed can still be null and I expect that the method throws NPE in this case. Last, but not least there is another danger in introducing Optional: the caller may pass an Optional embracing an object that is not a Date. Generics can be circumvented in Java easily, and a sloppy coder may pass a wrong Optional. It means that you have to implement assertions in your method:

  • Argument is not null,
  • Argument is of the proper type.

Also recall that Optional, in case of a method return value says: I do not trust you handling null properly, therefore I give you a wrapped object so you have to handle optionality explicitly. What would this message be when you create the API requiring Optional as an argument? Please do not trust me! Give me only Optional because even I do not trust myself to handle a null value properly. Weird… On the other hand I trust that you will not pass null or a wrong type.

In my opinion: in this case using Optional does not deliver more value than having proper documentation for the API and does not force the caller to behave better than it would anyway. On the other side you put extra code on your own shoulders.

Give Optional to code you trust, accept it from code that does not trust your code, but do not request it! Trust yourself!

Private Optional Fields

When you declare a local, private field to be Optional you will force the developer of the class itself to pay more attention to the optional feature of the field. The cost of this is the extra wrapper, the extra clutter in the code handling optional. On the other side there is no much gain, because you can get the same level of quality extending your unit tests checking all cases where null value of the field is to be considered. Since all the code is in the hand of the current developer being responsible for the whole code there is no benefit of Optional. It is again, like you not trusting yourself. That is a serious issue needing more and different treatment than what Optional Java class can provide.

Optional in Functional Programming

You can use Optional to program Java in the functional programming style if you want, but Java is not a functional language and optional and lambda and the functional style methods alone will not make it one. But that is a different topic for later.

Microservices for Java, explained. Revitalize your legacy systems (and your career) with Reactive Microservices Architecture, a free O'Reilly book. Brought to you in partnership with Lightbend.

Topics:
java 8 ,optional ,collections ,programming style ,functional programming

Published at DZone with permission of Peter Verhas, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

The best of DZone straight to your inbox.

SEE AN EXAMPLE
Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.
Subscribe

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}