o9s
is a microblog
home archives search feed blogroll


Get Rid Of Null Checks With Null Objects

You’ve been assigned an Android project. You retrieve this JSON from a REST API.

[
  {
    ticket_id: 1,
    ticket_name: "The Car Show",
    ticket_holder: {
      first_name: "John",
      last_name: "Doe",
      email: "john@doe.com"
    }
  },
  {
    ticket_id: 2,
    ticket_name: "The Train Show",
    ticket_holder: null
  }

You write your own parser. It looks something like this.

class TicketHolder {
  String firstName;
  String lastName;
  String email;

  // Getters and setters.
}

class Ticket {
  int id;
  String name;
  TicketHolder holder;

  // Getters and setters.
}

class TicketResponse {
  public static List<Ticket> getTickets(JSONArray jsonArray) {
    // [...]

    for (int i = 0; i < jsonArray.length(); i++) {
      // [...]

      if (jsonTicketHolder != null) {
        ticketHolder = new TicketHolder(firstName, lastName, email);
      } else {
        ticketHolder = null;
      }

      ticket.setTicketHolder(ticketHolder);

      // [...]
    }

    // [...]
  }
}

It works well. But there’s an issue. Every time you want to access the ticket holder informations, you have to perform a null check. ticket.getTicketHolder().getFirstName() will result in a NullPointerException if the ticket has no ticket holder. It’s all because of the line ticketHolder = null;.

You can fix this by adding a class to your project.

class NullTicketHolder {

  public String getFirstName() {
    return "";
  }

  public String getLastName() {
    return "";
  }

  public String getEmail() {
    return "";
  }

}

You can now replace the line -

ticketHolder = null;

- with -

ticketHolder = new NullTicketHolder();

By performing these changes, you can stop null checking ticket.getTicketHolder(). It works by replacing if conditionals with polymorphism. You can implement any default behavior you desire in NullTicketHolder. Maybe you want the default first name to be John? Then use return "John"; instead of return "";.

The downside is that you now have to keep two APIs in sync. Both TicketHolder and NullTicketHolder have to inherit from the same class or interface. An interface makes more sense in this case since there’s no implementation necessary in the parent’s methods, you only need the method signatures.

interface TicketHolderInterface {
  String getFirstName();
  String getLastName();
  String getEmail();
}

Don’t forget to change -

class TicketHolder

- to -

class TicketHolder implements TicketHolderInterface

- and -

class NullTicketHolder

- to -

class NullTicketHolder implements TicketHolderInterface

The code is not going to work otherwise. The classes need to have the same parent or else you won’t be able to use polymorphism.

Posted on 2018-02-12   #designpattern     #android     #java  






← Next post    ·    Previous post →