try..catch VS long if() [duplicate]

2019-07-19 22:17发布

问题:

This question already has an answer here:

  • Null check chain vs catching NullPointerException 19 answers

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?

回答1:

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);