A practice I’ve used recently and found quite helpful is to wrap the return type of newly created getters inside an Optional.

With the pre-java 8 approach of not wrapping in Optional, we end up with verbose defensive code that contains a lot of nested if (xx != null), or worse, NPEs in production when some getter in the call chain returns a null, which can happen in a lot of scenarios.

As an example:

class Trip {
   private TripDetails tripDetails;

   public TripDetails getTripDetails() {
      return tripDetails;
   }
}

class TripDetails {
   private Traveller traveller;

   public Traveller getTraveller() {
      return traveller;
   }
}

class Traveller {
   private String name;

   public String getName() {
      return name;
   }
}

Having a trip object, we would usually get the traveller name either by using defensive programming, or not doing checks for nulls:

The first option produces code that is clearly too verbose with three nested ifs that hide the business logic and clutter the code.

String travellerName = null;
if(trip != null) {
   TripDetails tripDetails = trip.getTripDetails();
   if(tripDetails != null) {
      Traveller traveller = tripDetails.getTraveller();
      if(traveller != null) {
         travellerName = traveller.getName();
      }
   }
}

On the other hand, just forgetting to check for nulls would have the following code throw NPEs in production for some use cases:

String travellerName = trip.getTripDetails()
      .getTraveller().getName();

The alternative is to wrap the return object inside an Optional, so the getters would become

public Optional<TripDetails> getTripDetails() {
   return Optional.ofNullable(tripDetails);
}

public Optional<Traveller> getTraveller() {
   return Optional.ofNullable(traveller);
}

public Optional<String> getName() {
   return Optional.ofNullable(name);
}

That way we would have less verbose code that doesn’t throw NPEs.

If it’s okay that the travellerName is null, we’d write something like this:

String travellerName =
      trip.getTripDetails()
            .flatMap(TripDetails::getTraveller)
            .flatMap(Traveller::getName)
            .orElse(null);

If we need to throw an exception when we don’t have a travellerName, we’d use the orElseThrow method:

String travellerName =
  trip.getTripDetails()
        .flatMap(TripDetails::getTraveller)
        .flatMap(Traveller::getName)
        .orElseThrow(() ->
            new RuntimeException("Traveller name can't be null"));

When using Optional, if any of the intermediate calls returns a null value, the following intermediate calls aren’t executed, and only the terminal operation orElse / orElseGet / orElseThrow is executed, preventing an NPE exception while having clear and concise code.