Don’t Hide Standard Libraries behind Facades!
From time to time one needs to check whether an argument or a variable is null, and in Java you can do that in (at least) two ways: compare it directly to null (obj == null), or use the method Objects.isNull(obj). But sometimes I come across code bases where they have chosen to create a third option: a separate method, usually in a utility class, and typically named isObjectNull(obj). Is that a smart thing to do?
Let’s start with a short note on the Objects.isNull(obj) method. First of all, the method wasn’t included in the first versions of the Java language. When we check the documentation, we quickly find out why: “This method exists to be used as a Predicate, filter(Objects::isNull)”. It doesn’t look like its designers intended it to be used in if statements to check whether an object is null, because in those cases you can simply use a direct comparison with null. But the method certainly comes in handy in predicates. In case you wondered though, the implementation is indeed as simple as “return obj == null;”. In other words, there’s no additional magic to be found in Objects.isNull(obj) beyond a simple check whether the argument is null.
An extra method call, but only in theory
Given that the implementation of Objects.isNull(obj) is nothing more than a direct comparison with null, one might wonder what the drawback is of using this method. I see possibly two of them, though I’m not so sure whether they also have any practical consequences.
The first drawback is that using Objects.isNull(obj) may confuse developers who are not so familiar with the method. They may think that it actually does something more than just a comparison to null, and therefore start to use it just because they see other developers doing it and assume it may be a smart thing to do. Or it could be the opposite: they stay away from the method because they’re not sure what it really does. Practically speaking, it makes little difference though. In fact, I would say that worst case, this is a symptom of a totally different problem, namely a knowledge problem. If that is indeed the case, it’s most probably not limited to just this part of the standard Java libraries either.
The other drawback is that using Objects.isNull(obj) implies an additional method call, and this may have a negative effect on performance. Or has it? What will happen in practice is that the compiler will quickly find out that the logic from Objects.isNull(obj) can be inlined wherever it has been used. Inlining means that the operations in the method’s body are copied over to the place where the method is being called from. The result is that in the end, there’s no real call to Objects.isNull(obj), but just a local comparison with null.
Using Objects.isNull(obj) or not is therefore mostly a matter of taste and preference. But even if it doesn’t really make a difference for the computer: is it really necessary to give the compiler an extra task, i.e. inlining your calls to Objects.isNull(obj)? No matter how small or trivial that extra task is, it is an extra expense, so I tend to go for a direct comparison with null anyway.
Adding another method call
The challenge to the compiler becomes even worse if you choose to put the call to Objects.isNull(obj) behind your own facade method. That is, if it really can be called a facade method in the first place, because it’s hardly a simplification to hide the method call Objects.isNull(obj) behind a another method named ObjectUtils.isObjectNull(obj). And when two alternatives already exist, there is no need to build a third one. Also, the challenge to the compiler became a bit more complicated: it doesn’t need to inline just a method call, but has to discover that it can inline operations that are two method calls away!
But this practice is also a bad idea for readability. One can expect an average Java developer to know what Objects.isNull(obj) is and isn’t without having to look it up. But the same can’t be said about your local ObjectUtils.isObjectNull(obj) without the developer having checked out the documentation and/or its implementation. Could it be doing some logging too? Or is there another side effect? Does it really only check if the object is null, or is it so “convenient” that it also returns true if it’s an empty String or Collection? The biggest problem is probably that your code base contains both both == null, Objects.isNull(obj) and ObjectUtils.isObjectNull(obj), depending on which developer wrote the code at what time. As a new developer, you can only wonder what’s correct and why.
Some argue that it’s nevertheless a good idea to create facade methods in front of standard libraries, so that you have the option to make small changes to the behavior. I would argue that that’s a bad idea, for two reasons. One reason is that you’re spending time to plan and cater for an eventuality that may never occur. The other reason would be to actually make such a change. Who wants to take the risk to change the behavior of a basic method that has been used in many places in the code base? Even with full test coverage on all methods and high-quality unit tests, I would be very skeptical to do something like that.
Don’t create facade methods unless you know why you need them
But once you’ve started creating facade methods in front of the standard libraries, the question is: how many of them should you create, just because it might be nice to be able to add some extra functionality to one of the basic operations some time in the future? Best case they don’t make a difference — if the compiler manages to in-line everything. But I’ve also seen attempts to reimplement methods like Collection.contains(element) that didn’t look optimal, to say the least. I’m sure there are code bases out there with different variations of such implementations as well, one being worse than the other.
Does that mean you should never create facade methods in front of standard libraries? Not really. In fact, from time to time it happens that I create a small facade myself, but only when I have a good reason. An example would be when I need to use Random for some functionality, and at the same time need to be able to run the unit tests in a deterministic way. In such cases, it’s nice to have a facade method that routes its calls to java.util.Random at runtime, but connects to the well-known XKCD version of random 4 while running unit tests. It’s basically a poor man’s mock, but if this is what it takes to avoid dragging in a mock framework in my project, then I think it’s worth it. But I don’t think I will be using Objects.isNull(obj) in any of my code bases anytime soon.
This article originally appeared in Kode24 in Norwegian under the title “Filip er lei av fasader: — Skal mye til før jeg bruker dette i koden min”.