9

In code we have got a lot of chain methods, for example obj.getA().getB().getC().getD(). I want to create helper class which will check if method getD() isn't null, but before that I need to check all previous getters. I can do it in this way:

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

or (which is "silly")

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

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

I think that the best will be:

  1. obj.getA().getB().getC().getD().isNull() - for this purpose I will need to change all of my getters, for example implement some interface which contains isNull() method.
  2. NullObjectHelper.isNull(obj.getA().getB().getC().getD()); - this will be the best (I think so) but how to implement this?
pepuch
  • 6,346
  • 7
  • 51
  • 84
  • 5
    Solution. Refactor. Don't do chaining #LawOfDemeter – user802421 Oct 28 '13 at 08:37
  • 1
    @user802421 I don't want to refactor whole application, it's to big. All I want to do is to create some helper class. I agree with you that refactor will be the best but we haven't got time. – pepuch Oct 28 '13 at 08:38
  • I don't see how your two "solutions" would help with intermediate results being `null` – Henry Oct 28 '13 at 08:55
  • I want to use it in this way `if (NullObjectHelper.isNotNull(obj.getA().getB().getC().getD())) {} else {}`. If this is bad idea what should I do/use? – pepuch Oct 28 '13 at 08:56
  • I'm basically with the other commenters, but you might have a look at using AOP, depending on the context. See [this answer](http://stackoverflow.com/a/9211946/687514) – Anders R. Bystrup Oct 28 '13 at 09:16
  • Migrate to [kotlin](https://kotlinlang.org/) (if it possible) and enjoy! – JustAnotherCoder Apr 21 '20 at 09:31
  • I don't code in java, but while searching for php pages to close as dupes, I arrived here. PHP8 now offers the nullsafe operator: https://stackoverflow.com/q/12351737/2943403 (seems like a case of right solution, wrong language) – mickmackusa Nov 28 '20 at 20:38

3 Answers3

10

As of Java 8 you can use methods like Optional.isPresent and Optional.orElse to handle null in getter chains:

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

While this is preferable to catching NullPointerException the downside of this approach is the object allocations for Optional instances.

It is possible to write your own static methods that perform similar operations without this overhead:

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

For a sample implementation, see the Nullifier type here.

No approach is likely to have greater runtime efficiency than nested if-not-null checks.

McDowell
  • 107,573
  • 31
  • 204
  • 267
  • 1
    to do in one line Optional.ofNullable(obj) .map(Obj::getA) .map(A::getB) .map(B::getC) .map(C::getD).orElse(objDefault); – Abs Feb 03 '19 at 23:05
7

You can achieve the desired result with Option pattern. This enforces you to change a method signature, but basically if your method returns some type T, it guarantees it has some non-null value, and if it returnsOption<T> it means it either has value T, or null.

Java 7 had some feature called null safety, but it was removed from the final release. You could do:

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

Moreover, Java 8 will add a feature called Optional so you would do it safely.

In fact, if you really want to use that now, try Null Object pattern. It means that instead of returning plain null you can return some sort of default value, which won't trigger NullPointerException. Though, you need 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 utility to do it you can wrap it in 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 the following:

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

It won't require you to change existing functionality

mishadoff
  • 10,719
  • 2
  • 33
  • 55
  • +1 Thanks mishadoff for suggestion. I know that I can use `Null object` pattern but if I will use it I will need to make some changes to application. I don't want to do it because application is almost finished and I'm new in this project. – pepuch Oct 28 '13 at 10:59
1

As already stated, the true solution is refactoring.

In the meantime, you could just 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
    }
}

At the caller site:

D d = getD(obj);

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


I don't see how the two options you list at the end of your question would help if any of the intermediate getX() returns a null; you will get a NullPointerException.

Ali
  • 56,466
  • 29
  • 168
  • 265
  • To avoid NPE in the last example, we can wrap code in Runnable block and call later with try-catch. – mishadoff Oct 28 '13 at 11:38
  • I wouldn't recommend the actual code you've used at all. It sounds like it's usual for A or B or C to possibly be null, so it's generally a bad idea to go to the expense of throwing an exception in this case. Wrapping things in a utility method is a good approach, for sure. However I'd *much* rather the utility method included the "silly" code that does null-checking rather than being lazy and catching exceptions. – Andrzej Doyle Oct 28 '13 at 15:54
  • @AndrzejDoyle **And I would recommend refactoring in the first place.** Potentially null objects and chained getters are the signs of flaws. My problem with the "silly" code is that it is error prone: it is easy to do a typo there, or miss a null check, etc. We can argue about the pros and cons of the try-catch vs. "silly" snippets but the solution would be to refactor the code so that we don't need any of them... The wrapper function (doesn't matter whether the try-catch or the "silly" snippet is used) at least helps keeping the new codes *relatively* clean; that's my point. – Ali Oct 28 '13 at 16:04
  • @Ali Sure, I can agree with all that. I overlooked the importance of the first line in your answer (you'd think something would have **drawn my attention to it**, but apparently not!). – Andrzej Doyle Oct 28 '13 at 16:29