PUBLIC OBJECT

A simple pattern for avoiding NullPointerExceptions

Imagine you've got some method that sometimes returns a legitimate value, and other times returns the special value null to indicate that no legitimate value exists:

public interface StoreLocator {
  /**
    * Returns a store nearest to {@code address}, or {@code null}
    * if there are no stores within delivery range of the address.
    */
  PizzaStore findNearbyStore(Address address);
}

Why returning null is annoying

Since it can return null, we need to check for that whenever we call the method:

public Receipt createReceipt(Order order) {
    ...

    PizzaStore closestLocation 
        = storeLocator.findNearbyStore(order.getDeliveryAddress());
    if (closestLocation == null) {
      throw new IllegalArgumentException("No stores nearby!");
    }
    if (!closestLocation.equals(order.getStoreAddress())) {
      receipt.addMessage("Next time you order a pizza, consider"
          + " our closer %s location", closestLocation);
    }

    return receipt;
}

Why returning null is dangerous

In another scenario we might forget to check for null, and end up creating corrupt data. The invalid null value might not be discovered for a long time - it might even get persisted in your database. For example:

public Order createOrder(Address toAddress, List<LineItem> lineItems) {
    PizzaStore store = storeLocator.findNearbyStore(toAddress);
    return new Order(toAddress, lineItems, store);
}

A simple fix - two methods

Provide two methods to cover the two interesting cases: where there's always a legitimate value, and where there's only sometimes a legitimate value:

public interface StoreLocator {
  /**
   * Returns a store nearest to {@code address}.
   *
   * @throws IllegalArgumentException if there are no stores
   *     within delivery range of the address.
   */
  PizzaStore findNearbyStore(Address address);

  /**
   * Returns a store nearest to {@code address}, or {@code defaultValue}
   * if there are no stores within delivery range of the address.
   */
  PizzaStore findNearbyStore(Address address, PizzaStore defaultValue);
}

It's simple and it makes for a user-friendly API. It's particularly nice when the defaultValue fits the problem neatly:

public Address getCustomerServiceAddress(Address customerAddress) {
    return storeLocator.findNearbyStore(
        customerAddress, PizzaStores.HEAD_OFFICE).getAddress();
}