Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Check if any object in get chain is null without having to check each depth [duplicate]

I'm working with a legacy application where I often have to access properties deeply nested like that:

a.getB().getC().getD().getE().getF()

The problem is that it's possible that in any depth, the value could be null. Of course I could check each depth like that:

public Optional<F> retrieveValue(A a) {
  if(a != null && a.getB() != null && a.getB().getC() != null && 
     a.getB().getC().getD() != null && 
     a.getB().getC().getD().getE() != null && 
     a.getB().getC().getD().getE().getF() != null) {
    return Optional.of(a.getB().getC().getD().getE().getF());
  } else {
    return Optional.empty();
  }
}

F existingOrCreated = retrieveValue(a).orElse(new F());

But I have to do this in many places for many different objects so the code gets bloated with these checks. Mostly the objects are non null but there are some rare cases where objects are null. Is there a way to do it in a more concise way? I'm using Java 8 but I can't update the legacy code provided.

like image 348
Christian Avatar asked Sep 10 '19 19:09

Christian


1 Answers

Before going into my answer I'd like to point out that these chains should be avoided in the first place. (Check the Law of Demeter).

Now to the problem. Because Java, unlike other languages like Kotlin does not provide simpler checking for nulls, until Java 8 you had only the choice to check each level of your object.

But since Java 8 offers function passing as parameters, I started using this feature to build my own "Safe Calls" in Java:

public static <T> Optional<T> retrieveValue(Supplier<T> getter) {
  try {
    return Optional.ofNullable(getter.get());
  } catch (NullPointerException e) {
    return Optional.empty();
  }
}

Let's first see how this method is called in your given case:

F f = retrieveValue(() -> a.getB().getC().getD().getE().getF()).orElse(new F());

As you can see, we just pass a Supplier to retrieveValue and call it in a try-catch block where we catch the possible NullPointerException and return an Optional.empty() in that case.

A small disadvantage of this try-catch approach is, that it's slower than simple null check in the code if a NullPointerException occurs during checking.

Another advantage of this approach is, that this method is reusable for any other null checking in any depth and does not depend on a specific object structure.

Node node = retrieveValue(() -> root.getNode().getNode()).orElse(new Node());
like image 197
Christian Avatar answered Nov 06 '22 11:11

Christian