What does that deeply nested if statement do exactly?
The last couple of weeks I’ve been doing some java programming for the first time in 5 years, and something that my Scala tuned brain has had a hard time readjust to, is nested if statements with returns in them .
Traditionally Java code has quite a lot of
if (someValue != null) checks to avoid the dreaded
NullPointerException . In Java 8
java.util.Optional was introduced to mitigate some of this, but if you use a combination of
if (someOptional.isPresent()) and
someOptional.get() you could end up with just as many nested
ifs as you would using traditional
_ != null style. In my view this way of doing control flow is quite hard to follow and leads to high Cyclomatic Complexity .
Lets look at an example that I encountered recently (the code has been somewhat altered to protect the innocent):
As we can see the nesting goes deep, and there are several places where the code can “escape” via a return. It’s not obvious what the result will be in any given situation, at least not to me.
I started to think about how I would have solved this particular problem in Scala and I recalled that a former colleague of mine had given me a tip about a functional library for Java called Javaslang . I decided to see if I could solve this problem in a Scala’ish style using that library.
My first attempt looked like this:
It was slightly better than the original as the different operations where separated out into functions that was called from one quite compact return statement at the end. However I thought it had some shortcommings:
- There where still some nested if statements with returns in them .
11actually discards it’s argument and performs a side effect using the
userargument from the encapsualting function instead.
This code could also have been accomplished using the methods available on
java.util.Optional , so there wheren’t really any good reason to introduce Javaslang just to do it this way. Javaslang had another trick up it’s sleeve however, one that it has borrowed from languages like Scala and Haskell, namely Pattern matching .
Using that as an approach, I landed on this solution:
So what did we gain from this?
- If we count the
Matchas one Cyclomatic Complexity point, non of the three code blocks gets above 4.
- The extraction syntax of Pattern Matching gives us the power to check both that the
Optionis non empty and it’s value fulfils a predicate in one swoop.
- The alignment of the the
Caselines makes for great readability (in my view).
- If you get used to the style of looking at the last line/block of a method for it’s return statement, you’ll usually find a compact and concise definition composed of functions doing one separate thing.
Last, but not least, I’ve also included a Scala version of the same solution for comparison.
转载本站任何文章请注明：转载至神刀安全网，谢谢神刀安全网 » Battling Cyclomatic Complexity in Java Using Javaslang