After the article of last week “Optional in collections” today I can’t help but talking a bit more about the same beast. A bit more detail.
The class Optionial originally introduced by Google Guava and later included in the Java 8 package is simply 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. The wrapping code, the class Optional insist that the object wrapped is not null. 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 coder does 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 about it, just hope that you have the luck and a software bug will not select your house, bank account or body (in case of medical device) in a “bomb” explode there. 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.
“Code working” and “possible to understand” are the very basic requirement for software. Some old times we said that if the software runs then it was ok and for the maintenance it was enough if there were two “person” 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 create a working modified code that still works, easy to understand and to modify. This is the point where we get to the point of Optional.
When a method returns Optional is 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 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 introducing Optional: the caller may pass an Optional embracing an object that is not a Date. Generics can be circumvented in Java easy 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 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 shoulder.
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 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 to be. But that is a different topic for later.