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

How to Deal With Nested Conditionals (Part 2)

DZone's Guide to

How to Deal With Nested Conditionals (Part 2)

Nesting your conditionals, or inheriting pre-nested ones, can be a nightmare in the making. Fortunately, you can consolidate your code or implement a testing interface.

· Java Zone
Free Resource

Just released, a free O’Reilly book on Reactive Microsystems: The Evolution of Microservices at Scale. Brought to you in partnership with Lightbend.

In my previous post, I mentioned Decomposing Conditional and Consolidate Conditional Expression for nested conditionals. The problem was not only the nested conditions but also duplicated code fragments and lots of null object controls. In this post, I will cover Consolidate Duplicate Conditional Fragments and Testing Interface to tackle the above-mentioned problems.

Consolidate Duplicate Conditional Fragments

Martin Fowler proposed that “if the same fragment of code is in all branches of a conditional expression, move it outside of the expression” in his book. In this case, only else branches have duplicate code fragment but we can use Consolidate Duplicate Conditional Fragments refactoring for our problem as well. Consider the following code:

response = new RetrieveMarketInquiryCustomerResponse();
if(condition1){
   if(condition2){
      if(condition3){
       ...
      } else {
        log.debug("retrieveCitizenAddResponse==null");
        marketInqCustomerVo.setAddress(" ");
        marketInqCustomerVo.setCity("7089708790");
        marketInqCustomerVo.setDistrict("UNKNOWN_DISTRICT__ID");
        response.setMarketInqCusVo(marketInqCustomerVo);
      }
   } else {
     log.debug("retrieveCitizenAddResponse==null");
     marketInqCustomerVo.setAddress(" ");
     marketInqCustomerVo.setCity("7089708790");
     marketInqCustomerVo.setDistrict("UNKNOWN_DISTRICT__ID");
     response.setMarketInqCusVo(marketInqCustomerVo);
  } else {
       log.debug("retrieveCitizenAddResponse==null");
       marketInqCustomerVo.setAddress(" ");
       marketInqCustomerVo.setCity("CT200703022025160219");
       marketInqCustomerVo.setDistrict("UNKNOWN_DISTRICT__ID");
       response.setMarketInqCusVo(marketInqCustomerVo);
 }


Step 1: Since the same code occurs in each else branch, we can move it to the outer else, such that:

if(condition1){
   if(condition2){
      if(condition3){
       ...
      }
} else {
     log.debug("retrieveCitizenAddResponse==null");
     marketInqCustomerVo.setAddress(" ");
     marketInqCustomerVo.setCity("7089708790");
     marketInqCustomerVo.setDistrict("UNKNOWN_DISTRICT__ID");
     response.setMarketInqCusVo(marketInqCustomerVo);
}


Step 2: Applying Consolidate Conditional Expression. In other words, shrink nested if statements in:

if(condition1 && condition2 && condition3){
 ...
) else {
    log.debug("retrieveCitizenAddResponse==null");
    marketInqCustomerVo.setAddress(" ");
    marketInqCustomerVo.setCity("CT200703022025160219");
    marketInqCustomerVo.setDistrict("UNKNOWN_DISTRICT__ID");
    response.setMarketInqCusVo(marketInqCustomerVo);
}


Step 3: Then one more refined version with Decomposing Conditional and extracting the else part into a separate function.

if(isValid()){
 ...
) else {
    setResponse();
}

private boolean isValid(){
    return (condition1 && condition2 && condition3);
}

private void setResponse(){ 
    log.debug("retrieveCitizenAddResponse==null");
    marketInqCustomerVo.setAddress(" ");
    marketInqCustomerVo.setCity("CT200703022025160219");
    marketInqCustomerVo.setDistrict("UNKNOWN_DISTRICT__ID");
    response.setMarketInqCusVo(marketInqCustomerVo);
}



Using a Testing Interface

I still have another problem with my beast function — null checks! Although I am not sure how to apply it my current project, I would like to share the theory based on the book.

if (blalba != null){...}


This is a tricky problem, and the solution depends on the circumstances. One option is “if you have repeated checks for a null value, then replace the null value with a null object.”

In my case, though, it doesn’t fit for my problem. If there are many different classes to be checked, you need to add an isNull() operation to the class that you make a null check with. I need to modify five classes just for that function, but 31,533 for the whole system! In my opinion, there should be a consensus about the necessity of introducing null objects among the team. Maybe, only the subset of the most frequently used null classes will be created. What do you think?

As I need lots of classes and don’t want to modify all 31,533 of them, I prefer another option — "using a testing interface." Consider the following example:

Step 1: Create a null interface with no methods defined:

interface Nullable { }


Step 2: Implement Nullable in my null objects:

class NullOrganization extends RetrieveOrganizationAddressPhoneInfoResponse implements Nullable{

}


Step 3: Test for nullness with the instanceof operator:

retrieveOrganizationAddressPhoneInfoResponse = retrieveOrganizationAddressPhoneInfo();
Address address = retrieveOrganizationAddressPhoneInfoResponse.getAddresses(); 
if ( !(retrieveOrganizationAddressPhoneInfoResponse instanceof Nullable) && !(address instanceof Nullable)) { 
   ... 
}


And there you have it. Now you can use a testing interface to help handle null checks.

Strategies and techniques for building scalable and resilient microservices to refactor a monolithic application step-by-step, a free O'Reilly book. Brought to you in partnership with Lightbend.

Topics:
refactoring ,java ,tutorial ,conditionals ,nesting

Opinions expressed by DZone contributors are their own.

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

{{ parent.tldr }}

{{ parent.urlSource.name }}