Make sure the last getter in the method chain is not zero.

In the code, we have many chain methods, for example obj.getA().getB().getC().getD() . I want to create a helper class that checks if the getD() method is not empty, but before that I need to check all the previous getters. I can do it like this:

 try { obj.getA().getB().getC().getD(); } catch (NullPointerException e) { // some getter is null } 

or (which is "stupid")

 if (obj!null && obj.getA()!=null && obj.getA().getB()!=null && ...) { obj.getA().getB().getC().getD(); } else { // some getter is null } 

I do not want to check it every time using try{} catch() in my code. What is the best solution for this?

I think the best would be:

  • obj.getA().getB().getC().getD().isNull() - for this I will need to change all my getters, for example, implement an interface containing the isNull() method.
  • NullObjectHelper.isNull(obj.getA().getB().getC().getD()); - it will be better (I think so), but how to implement it?
+7
java design-patterns
source share
3 answers

You can achieve the desired result using the Option template. This forces you to change the signature of the method, but basically, if your method returns some type T , it ensures that it has some non-zero value, and if it returns Option<T> , then it either has the value T or null.

Java 7 had a feature called zero security, but it was removed from the final release. You can do:

 obj?.getA()?.getB()?.getC()?.getD() 

In addition, Java 8 will add a function called Optional so you can do it safely.

In fact, if you really want to use this now, try the Null Object template. This means that instead of returning plain null you can return some default value that will not throw a NullPointerException. Although you need to add some changes to your getters

 class Object { A getA() { // ... return a == null ? A.NULL : a; } } class A { static A NULL = new A(); // some default behaviour B getB() { if (this == NULL) return B.NULL; // ... return b == null ? B.NULL : b; } } 

EDIT: If you want to do this, you can transfer it to some functional interface and then call it.

 static boolean isNullResult(Callable call) throws Exception { try { return call.call() == null; } catch (NullPointerException npe) { return true; } } 

Usage will be as follows:

 isNullResult(new Callable<Integer>() { @Override public Integer call() throws Exception { return new A().getB().getC().getInt(); } }); 

This does not require a change in existing functionality.

+7
source share

With Java 8, you can use methods such as Optional.isPresent and Optional .orElse to handle null in hatcher chains:

 boolean dNotNull = Optional.ofNullable(obj) .map(Obj::getA) .map(A::getB) .map(B::getC) .map(C::getD) .isPresent(); 

Although it is preferable to detect a NullPointerException, the drawback of this approach is the allocation of objects for additional instances.

You can create your own static methods that perform similar operations without these utilities:

 boolean dNotNull = Nulls.isNotNull(obj, Obj::getA, A::getB, B::getC, C::getD); 

For an example implementation, see the Nullifier type here .

There is no approach that tends to be more efficient at runtime than nested if-not-null checks.

+2
source share

As already mentioned, the true solution is refactoring.

In the meantime, you can simply wrap your first workaround in a function:

 static D getD(MyClass obj) { try { return obj.getA().getB().getC().getD(); } catch (NullPointerException e) { return null; // Or even better, some default D } } 

On the caller’s website:

 D d = getD(obj); 

At the very least, you don't need to remove the caller using try-catch blocks. You still have to handle the errors in some way when part of the getX() intermediate call returns a null , and so d becomes null. It would be best to return the default d to the wrapper function.


I do not see how the two parameters that you list at the end of your question will help if any of the intermediate getX() returns null; you will get a NullPointerException .

+1
source share

All Articles