Table of contents
Welcome to the series "Java Coding"; brought to you by "Coding Mantis"!
At the beginning of my career, I faced quite a few cases where there were complex JSON structures, deeply nested within objects of objects, and trust me it was not enjoyable at all when I had to reach an element inside these structures to get its value. I thought at the time (well, I still do) that it was a bad design that would not follow me in the future.
Unfortunately, I was wrong; it did follow me because no matter how cleanly you design and implement something, at the end of the day the business wants what the business wants. Luckily, that does not mean our code should reflect this situation but we'll come back to this later on.
The Problem
While other languages were blessed with Elvis and other null-coalescing operators that made the approach to the above problem much easier, I was stuck in Java 1.6 writing null-checks upon null-checks, driving the cyclomatic and cognitive complexity through the roof and ensuring that every future developer that passed through my code would curse me for the abominations I was creating.
To shortly provide an example, it looked something like this:
MyObject myObject = new MyObject();
// indentation was not always there back then :')
if (classA != null
&& classA.getClassB() != null
&& classA.getClassB().getClassC() != null
&& classA.getClassB().getClassC().getClassD() != null
&& classA.getClassB().getClassC().getClassD().getValue() != null) {
myObject.setMyValue(classA.getClassB().getClassC().getClassD().getValue());
} else {
myObject.setMyValue(SOME_CONSTANT_VALUE);
}
return myObject;
Code blocks like these were eating away the lifespan of my keyboard's keys; of course, there were cases where it could get much worse than this. Maybe an array of objects would pop up every now and then, forcing me to iterate it and inside that loop to check again for null values. Absolute hell!
But one day, the music of angels started playing in my ears as the project got upgraded to Java 1.8 and my abominations could finally be refactored.
The Solution
Java 1.8 introduced a very helpful wrapper class to handle the absence of value, allowing us to drill down an object structure without having to write a single null-check and effectively reducing the cognitive complexity of blocks such as the above example for both the writer and the reader.
With much less verbose and way cleaner code due to lambdas and functional method invocations, the Optional wrapper was the answer to my prayers (although now I'd prefer to have something even less verbose).
Right away I started refactoring and ended up with code that allowed me to sleep at night:
MyObject myObject = new MyObject();
final String myValue = Optional.ofNullable(classA)
.map(ClassA::getClassB)
.map(ClassB::getClassC)
.map(ClassC::getClassD)
.map(ClassD::getValue)
.orElse(SOME_CONSTANT_VALUE);
myObject.setMyValue(myValue);
return myObject;
Conclusion
Java's Optional wrapper is a neat way to replace the arrays of if-else blocks from hell, "if-hells" if you will, when drilling down inside a structure with nullability in play and it allows us to write code that is much cleaner and more easily understandable for others and our future selves.
Of course, it's not only applicable in null-checks and it can have other usages as well, but this was an experiential post to share with you why its usage is of great benefit for us. For a more in-depth look at its applications make sure to drop a comment down below.
Alternatively, what do you think about the subject?