Java 8 Optionals for Null Objects

Reading Time: 2 minutes

In my previous post, I mentioned about refactoring techniques including testing interface for null checks. I have recognized that there is an alternative for it while reading Java 8 in Action: Lambdas, streams, and functional-style programming.

Optional Class

If there is an object that might contain a null value, we can use Optional to wrap the object in order to get rid of if-else statements. Let’s consider following code example:

CitizenAddressSet addressSet = new CitizenAddressSet().getAddressSet();
if (addressSet != null) {
   CitizenAddress address = addressSet.getAddressInfo();
   if (address != null) {
      AddressInfo residentialAddressInfo = address.getResidentialAddressInfo();
      if (residentialAddressInfo != null) {
      }
   }
}
public class CitizenAddress {
   private AddressInfo residentialAddressInfo;
   public void setResidentialAddressInfo(AddressInfo residentialAddressInfo) {
      this.residentialAddressInfo = residentialAddressInfo;
   }
   public AddressInfo getResidentialAddressInfo() {
      return residentialAddressInfo;
   }
}
public class CitizenAddressSet {
   private Set<CitizenAddress> addressSet;
   private CitizenAddress addressInfo;
   public void setAddressInfo(Set<CitizenAddress> addressSet) {
      this.addressSet = addressSet;
   }
   public Set<CitizenAddress> getAddressInfo() {
      return addressSet;
   }
   public CitizenAddress getAddressInfo() {
     return addressInfo;
   }
   public void setAddressInfo(CitizenAddress addressInfo) {
     this.addressInfo = addressInfo;
   }
}

My first attempt was using ofNullable() and map() of Optional. Wrap the null object using ofNullable() method, which returns an Optional wrapping the given value or the empty Optional if this value is null. Notice that we used get() to return the value of the Optional object for inner conditionals such as address.get(). Then, map() function applies the provided mapping function to it, if the value exists. If the Optional contains a value, then the function passed as argument to map transforms that value. Lastly, the client code looks like that:

//addressSets != null
Optional<CitizenAddressSet> addressSet= Optional.ofNullable(addressSets.getAddressSet());
Optional<CitizenAddress> address = addressSet.map(CitizenAddressSet::getAddressInfo);
		
//address != null
Optional<CitizenAddress> citizenAdress = Optional.ofNullable(address.get());
Optional<AddressInfo> residentialAddressInfo = citizenAdress.map(CitizenAddress::getResidentialAddressInfo);
		
//residentialAddressInfo != null
Optional<AddressInfo> addressInfo = Optional.ofNullable(residentialAddressInfo.get());
Optional<String> postalCode = addressInfo.map(AddressInfo::getPostalcode);

We get rid of if-else statements but if the wrapped value is null, get() throws a NoSuchElementException. For instance, if address and residentialAddressInfo is null, the following lines throw Exception in thread “main” java.util.NoSuchElementException: No value present. So, it is not a good replacement for null checks.

Optional<CitizenAddress> citizenAdress = Optional.ofNullable(address.get());
Optional<AddressInfo> addressInfo = Optional.ofNullable(residentialAddressInfo.get());

A possible solution is to modify the instance variable of the classes to Optional so that ofNullable does not affected by a null object. In this case, if getAddressInfo() and getAddressSet() functions return Optional, then we get rid of java.util.NoSuchElementException.

/**
 * Modified class for Optional instance variable
 * @author suleyman.yildirim
 *
 */
public class CitizenAddress {

 private Optional<AddressInfo> residentialAddressInfo;

 public void setResidentialAddressInfo(Optional<AddressInfo> residentialAddressInfo) {
    this.residentialAddressInfo = residentialAddressInfo;
 }

 public Optional<AddressInfo> getResidentialAddressInfo() {
    return residentialAddressInfo;
 }
}

/**
 * Modified class for Optional instance variable
 * @author suleyman.yildirim
 *
 */
public class CitizenAddressSet {

 private Optional<Set<CitizenAddress>> addressSet;
 private Optional<CitizenAddress> addressInfo;
 public void setAddressSet(Optional<Set<CitizenAddress>> addressSet) {
    this.addressSet = addressSet;
 }

 public Optional<Set<CitizenAddress>> getAddressSet() {
    return addressSet;
 }

 public Optional<CitizenAddress> getAddressInfo() {
    return addressInfo;
 }

 public void setAddressInfo(Optional<CitizenAddress> addressInfo) {
    this.addressInfo = addressInfo;
 }
}

Finally, our client code is cleaner and more readable! I hope you enjoyed reading. See you next time!..

Optional<CitizenAddressSet> addressSet = Optional.of(new CitizenAddressSet().getAddressSet());
addressSet.flatMap(CitizenAddressSet::getAddressInfo)
           .flatMap(CitizenAddress::getResidentialAddressInfo)
           .map(AddressInfo::getPostalcode) 
           .orElse("unknown");

Leave a Reply

Your email address will not be published. Required fields are marked *