2

I have a complex model structure in my project.
Sometimes I have to get a deep placed value from it. It looks like following:

something.getSomethongElse().getSecondSomething().getThirdSomething().getFourthSomething();

The problem is that each of those methods could return null, and I will get NullPointerException in case if it does.

What I want to know is should I write long if like

if(something != null && something.getSomethongElse() != null && something..getSomethongElse().getSecondSomething() != null && something.getSomethongElse().getSecondSomething().getThirdSomething() != null && omething.getSomethongElse().getSecondSomething().getThirdSomething().getFourthSomething() != null) {
    //process getFourthSomething result.
}

Or it is OK just to use try..catch like following:

SomethingFourth fourth = null;

try {
    fourth = something.getSomethongElse().getSecondSomething().getThirdSomething().getFourthSomething();
} catch (NullPointerException e) { }

if(fourth != null) {
    ///work with fourth
}

I know that NPE is a thing to be avoided, but isn't it overhead to avoid it in my case?

Vladyslav Matviienko
  • 10,610
  • 4
  • 33
  • 52

1 Answers1

2

If you can refactor the code and make each method return Optional. It will be possible to avoid null checks and try ... catch.

Optional<Result> result = something.getSomethingElse()
.flatMap(e -> e.getSecondSomething())
.flatMap(x -> x.getThirdSomething())
.flatMap(e -> e.getFourthSomething());
// at the end to check if result is present
result.ifPresent(..some_logic_here..); // or result.orElse(...);

so getSomethingElse() returns Optional<SomethingElse>, getThirdSomething() - Optional<ThirdSomething> and so on. We have to use here flatMap(Function<? super T,Optional<U>> mapper) because if the provided mapper is one whose result is already an Optional, and if invoked, flatMap does not wrap it with an additional Optional. In other words if map on map(e -> e.getSecondSomething()) the result type will be Optional<Optional<SecondSomething>> and we will have to do unnecessary get() call - map(...).get().map(...).

I hope this helps.

UPDATED You can do the same thing using method references.

Optional<Result> result = something.getSomethongElse()
            .flatMap(SomethongElse::getSecondSomething)
            .flatMap(SecondSomething::getThirdSomething)
            .flatMap(ThirdSomething::getFourthSomething);
Anton Balaniuc
  • 10,889
  • 1
  • 35
  • 53
  • Optinal? You must mean Optional but http://stackoverflow.com/questions/37960674/null-check-chain-vs-catching-nullpointerexception is much more detailed. – user6788933 Dec 06 '16 at 09:51
  • @user6788933, Thanks a lot for spotting the typo, I will update my answer. I agree that answer in other topic is more detailed. However my goal was just to show how to use Optional in this particular case. – Anton Balaniuc Dec 06 '16 at 09:58