Use of optional is optional
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.
Reference: | Use of optional is optional from our JCG partner Peter Verhas at the Java Deep blog. |
I use it in cached methods return values, if optional is null, it implies there is no entry in cache, if optional is not null but value is absent then the value is null in the cache for the key, otherwise, the caller has no clue whether what the null means.
The idea is to force the developer (it is the intention at least) to verify that a value or object reference is not null and thus ensure that operations he/she is performing are null safe operations, as Peter has mentioned in this article: “integer = methodReturningIntegerOrNull(); otherInteger = integer +1;” //Good way if (Optional.isPresent()){} //No so good if (object_optiona == null) Even with the advantages offered by the use of Optional, if there is not an object within the Optional and the developer does not prove it, but he / she uses the Optional.get () method immediately, it is likely… Read more »
Completely agreed that while NPEs can still happen unless developer correctly uses optional, my use case was about returning an object from a cached method that differentiates whether the element not exists in cache vs element exists and it’s value is null.
May be I should also change this to always return optional with a wrapped object that holds null. Or an optional containing optional?
In that situation you have three different cases: – value is not cached – value is cached and it is null – value is cached and it is not null In your data model you separate these three cases into two branches, something like – value is not cached (return value is null) or else – return the cached value wrapped in an optional that may be ‘absent’ Seems to be logical after I analyzed it. The problem is that this is logical only after you understood the intent of the developer. Java coding has to be simple and clear.… Read more »