There are two approaches you can take instead of returning null and these are:
- Using Exceptions
- Using the Special Case Pattern (Fowler)
This blog talks about using exceptions, and in this case I’m talking about checked exceptions, where the exception is used as a return type forcing your client code to take notice. I’ll try to explain what I’m talking about by using the usual contrived scenario of the type that you find in most programming books. The example I'll use is that of the ubiquitous employee details stored in a database and retrieved by some client code in the form of an Employee object using an EmployeeDAO.
Given that any and all our method signatures can return null, then some sample client code would look something like this:
EmployeeDAO instance = new EmployeeDAO();
// Get an existing employee and print the phone number
Employee employee = instance.getEmployeeByName("John", "Smith");
if ((employee != null) && (employee.getPhoneNumber() != null)) {
System.out.println("John Smith's phone number is:" + employee.getPhoneNumber());
}
// The same thing will happen if we ask for a list of employees by surname.
// We need to check for null
List<Employee> employees = instance.getEmployeesBySurname("Parker");
if (employees != null) {
for (Employee item : employees) {
if ((employee.getPhoneNumber() != null)) {
System.out.println(item.getFirstName() + " " + item.getSurname()
+ "'s phone number is:" + item.getPhoneNumber());
}
}
}
// Whoops we've forgotten the null check
employee = instance.getEmployeeByName("Wil", "Johnson");
System.out.println("Wil Johnson's phone number is:" + employee.getPhoneNumber());
… and ALL clients would have to do these checks.
Using checked exceptions, we can tidy this code up somewhat by firstly changing our method signatures to throw exceptions
public Employee getEmployeeByName(String firstName, String surname)
throws NoDataAvailableException;
public List<Employee> getEmployeesBySurname(String surname)
throws NoDataAvailableException ;
...and then simply adding a try / catch block to our client code:
try {
EmployeeDAO instance = new EmployeeDAO();
// Get an existing employee and print the phone number
Employee employee = instance.getEmployeeByName("John", "Smith");
System.out.println("John Smith's phone number is:" + employee.getPhoneNumber());
// Try to get all employees with the surname 'Parker'
List<Employee> employees = instance.getEmployeesBySurname("Parker");
for (Employee item : employees) {
System.out.println(item.getFirstName() + " " + item.getSurname()
+ "'s phone number is:" + item.getPhoneNumber());
}
} catch (NoDataAvailableException e) {
e.printStackTrace();
}
This obviously looks better than the first sample code, but the thing to note is that the general theme here is to force the Employee objects to do more work, which centralises responsibility for null, or special case checking in one location; hence, improving code quality and reducing the possibility of errors.
But, is using exceptions the best you can do? My next blog will talk about implementing the same scenario using Special Case Pattern, which to me is the best way of approaching this problem...
No comments:
Post a comment