Saturday, 30 April 2011

Null Return Values and the Special Case Pattern

My previous blog talked about the problems associated with nulls being somewhat awkward to deal with and how this problem can be mitigated using exceptions. From my last blog, you’ll also probably guess that I believe that even using exceptions isn’t great a idea and that the best approach is to force your objects to do even more work. This blog uses the same contrived employee details scenario to implement Martan Fowler’s Special Case Pattern.

The big idea behind this pattern is that for every ‘special case’ encountered in your code you return a special, or different, object. In our employee scenario, null is a special case and hence we return a NullEmployee object instead of returning null.


A good way of implementing a NullEmployee is as an immutable singleton, that way you don’t create a multitude of unnecessary objects and it’s thread-safe.

public final class NullEmployee extends Employee {

 
private static final String DEFAULT_VAL = "";
 
private static final NullEmployee instance = new NullEmployee();

 
/**
   * Object is an immutable singleton
   */
 
private NullEmployee() {
   
// Blank
 
}

 
@Override
 
public final String getFirstName() {
   
return DEFAULT_VAL;
 
}

 
@Override
 
public final String getSurname() {
   
return DEFAULT_VAL;
 
}

 
@Override
 
public final String getPhoneNumber() {
   
return DEFAULT_VAL;
 
}

 
/**
   *
@return Return the one and only immutable Null Employee
   */
 
public static Employee getInstance() {
   
return instance;
 
}
}

This means that any client code will not need to test for nulls:

    // This will NEVER throw a NullPointerException because of the NullEmployee object
    // that is returned if Bill Williams does not exist.
   
employee = instance.getEmployeeByName("Bill", "Williams");
    System.out.println
("Bill Williams phone number is:" + employee.getPhoneNumber());

   
// The same thing will happen if we ask for a list of employees by surname. If an empty
    // list is returned then nothing bad happens.
   
List<Employee> employees = instance.getEmployeesBySurname("Parker");
   
for (Employee item : employees) {
     
System.out.println(item.getFirstName() + " " + item.getSurname()
         
+ "'s phone number is:" + item.getPhoneNumber());
   
}

The only other detail to think about is the Employee. It has three fields: first name, surname, and phone number and whereas first name and surname are mandatory for our purposes, we might consider phone number as optional. This means there is the additional problem of the getPhoneNumber() method possibly returning null. This leads us to revisit or original employee code to ensure that optional fields also NEVER return null:

  public String getPhoneNumber() {
   
return phoneNumber == null ? "" : phoneNumber;
 
}

The benefits of using this pattern is that it achieves clean client code without no duplication of effort or code and with less likely-hood of NullPointerExceptions being raised.

2 comments:

Anonymous said...

Hi,
I have gone through your blogs and understood usage of Special Case Pattern. However I have doubt, what if I need to do something with the phone number of the Employee, and that is needed by another class. Now instead of null I will get an empty String. I am confused. Please explain More.

Thanks and Regards,
Saravanan.K

Roger Hughes said...

Thanks for getting in touch. The motivation for the Special Case Pattern is to make your code less brittle by avoiding NullPointerExceptions

In this example, if you don’t use the Special Case Pattern and the Employee does not have a phone, then the empty phone number attribute of the employee's record is null. Any client code that uses the phone number of the Employee class must either constantly check for a null value, or suffer a NullPointerException when the phone number is empty.

If you define an empty field as an empty string and not a null reference, then your client’s code won’t need to check for null and won’t crash. Furthermore, if the Employee class is used by 20 client’s, then by effectively moving the null check to inside the Employee, each of the 20 client’s don’t have to check for null saving a lot of time and effort.

Hope this answers your question.