Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

How to Deal With Nested Conditionals (Part 1)

DZone's Guide to

How to Deal With Nested Conditionals (Part 1)

It's fun looking over thousands of lines of code to see if-else statements wrapped in if-else statements, right? No. Here's how to approach refactoring nested conditionals.

· Java Zone
Free Resource

The single app analytics solutions to take your web and mobile apps to the next level.  Try today!  Brought to you in partnership with CA Technologies

In my current project, there are thousands of lines of code (LOC), some of which date back to 10 years ago. An important part of my day-to-day job is trying to understand and debug functions just like the following example (Listing 1). I omitted the boolean expressions and the code in branches, but there is still something wrong with it!

Listing 1:
public Response
function() {
    if () {
        if ()
            if () {
                if () {
                    if () {
                        for () {
                            if () {
                                if () {}
                            }
                        }
                    } else {}
                }
            } else {
                if () {
                    if () {}
                    if () {
                        for () {
                            // Line 21: see the code in listing 2
                            if () {
                                if () {}
                            }
                            // Line 26: see the code in listing 2 
                        }
                        if () {}
                    } else {}
                } else {
                    // Line 33: see the code in listing 3
                    if () {
                        if () {
                            if () {
                                // Line 37: see the code in listing 3
                                if () {}
                                if () {}
                                if () {
                                    if () {
                                        if () {
                                            if () {
                                                if () {
                                                    if () {
                                                        if () {}
                                                        if () {}
                                                    }
                                                } else {}
                                            } else {}
                                        } else {}
                                    }
                                } else {}
                            }
                        } else if () {
                            if () {
                                if () {
                                    if () {
                                        if () {
                                            if () {}
                                        }
                                        if () {
                                            if () {
                                                if () {} else {}
                                                if () {} else {}
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
    } else
    if () {}
    return response;
}


You might think, "What's the problem? If it's working, it's fine!" Indeed, it is working but:

  • Is it easy for you to read it?

  • Can you understand the execution flow?

  • What if you add new functionality to that function? Are you sure that you won't break existing requirements?

  • Have you heard of "cyclomatic complexity?"

  • How testable is that function?

I think somebody knows the answers: "Any fool can write code that a computer can understand. Good programmers write code that humans can understand," Martin Fowler, 2008.

The original code, 412 LOC in total, is much more complex in terms of readability and maintainability. There are multiple boolean expressions in almost every if statement; such as the code in Listing 2:

Listing 2:
if (retrieveIndividualCustomerAddressInfoResponse.getAddresses()[a].getContactType() != null && retrieveIndividualCustomerAddressInfoResponse.getAddresses()[a].getContactType().getValue() == SubContactTypeCS.POSTAL_ADDRESS) {
    if (retrieveIndividualCustomerAddressInfoResponse.getAddresses()[a].getPartyRoleInContactPointType() != null && retrieveIndividualCustomerAddressInfoResponse.getAddresses()[a].getPartyRoleInContactPointType().getValue() == PartyRoleInContactPointTypeCS.HOME) {
        ...
    }
}


Decompose Conditional

We can start refactoring with complicated conditionals. Extract methods for each boolean expression as follows. The result is still nested, but there is another technique — consolidating conditional expressions — that will help.

if (isValidContactType()) {
    if (isValidPartyRoleInContactPointType()) {
        ...
    }
}
private boolean isValidContractType(){
    return retrieveIndividualCustomerAddressInfoResponse.getAddresses()[a].getContactType() != null && retrieveIndividualCustomerAddressInfoResponse.getAddresses()[a].getContactType().getValue() == SubContactTypeCS.POSTAL_ADDRESS;
}

private boolean isValidPartyRoleInContactPointType(){ 
    return retrieveIndividualCustomerAddressInfoResponse.getAddresses()[a].getPartyRoleInContactPointType() != null && retrieveIndividualCustomerAddressInfoResponse.getAddresses()[a].getPartyRoleInContactPointType().getValue() == PartyRoleInContactPointTypeCS.HOME; 
}


Consolidate Conditional Expression

Another attempt to eliminate nested if-else statements could be combining multiple conditionals into a single conditional expression and extracting it; such as the code in Listing 3:

Listing 3:
if (customerType != Constants.CUSTOMERID) {
    if (customerType == Constants.XXX) {
        ...      
        if (retrieveCitizenResponse != null && retrieveCitizenResponse.getCitizen() != null) {
            ...
        }
    }
}


Step 1: Consolidate Conditionals Into One Statement

Listing 3 Step 1:
if (customerType != Constants.CUSTOMERID && customerType == Constants.XXX && retrieveCitizenResponse != null && retrieveCitizenResponse.getCitizen() != null) {
}


Step 2: Decompose Conditionals Into Relevant Functions

Listing 3 Step 2:
if (getCustomerType() && retrieveCitizenResponse()) {
  ...
}
private boolean getCustomerType (){ 
   return customerType != Constants.CUSTOMERID && customerType == Constants.XXX;
} 
private boolean retrieveCitizenResponse(){
   return retrieveCitizenResponse != null && retrieveCitizenResponse.getCitizen() != null;
}

CA App Experience Analytics, a whole new level of visibility. Learn more. Brought to you in partnership with CA Technologies.

Topics:
refactoring ,conditionals ,java ,tutorial

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}