Search code examples
javaif-statementjava-8sonarqubecode-complexity

Nested if-object-null-return method extraction or alternative for sonar cognitive complexity


In most cases when an object is optional, it is possible to use Guava to help in if null checks. But in cases where the statement is used to decide if the method is going to return earlier (from what I experienced) even that is not enough.

My question regards the use of nested if-statements to return a default value instead of continuing with the method execution.

Here's an example of what I mean:

private MyObject myMethod(Object object, Object object1, Object object2) {

    /* inherent implementations for first if-statement... */
    if (object == null) {

        /* inherent implementations for second if-statement... */
        if (object1 == null) {
            return new MyObject();
        }

        /* inherent implementations for third if-statement... */    
        if (object2 == null) {
            return new MyObject();
        }

    } else {

        /*same structure shown in if-statement...*/

    }

    /* inherent implementations before last return statement... */

    return new MyObject(/* with args */);

}

I am looking for a solution that solves the problems of cognitive complexity indicated sonarQube in which the amount of 'if' and nested 'if' statements used in the method increments the complexity of the code.

In other words, ways to extract the statements from the method into another method or solving them through other ways that don't involve if-statements.

EDIT(05/09): First, thanks for all of the answers provided, but I believe there's a bit of a detail I forgot to mention. Each of the /* implementations... */ that are mentioned in the code snippet I provided have some type of functionality that must be fulfilled before the next if-statement so suggestions like if (object1 == null || object2 == null) are a no-go. About the suggestion of using Java 9's Optional.or: from what I heard, Java 8 is the currently most stable version of Java so worst case scenario I would wind up having to wait for Java 11. Also each of the /* implementations... */ mentioned have to be executed in in order, so in order to make each of those details more explicit I have reworked a bit of the code snippet I provided earlier.


Solution

  • The answers from clean code perspective:

    • Don't go with so many arguments. It sounds silly first, but: the real answer is to design interfaces that take as few parameters as possible. So, instead of passing a, b, c as parameters one could create a class around them. Which gives you more options to think about default values, and so on.
    • Of course, early returns are possible as well.

    Your code says same structure as shown in if statement. Then the simple solution is to do

    if (object1 == null) return new MyObject();
    if (object2 == null) return new MyObject();
    

    once, before any other code. The point is to avoid the nesting of conditions. And when you just repeat conditions, then put them in a different place and avoid the repetition.