简体   繁体   中英

Check not null in Java

Imagine I have, say, XML-generated entity in Java that holds some data I need. For example:

<Car>
   <Engine>
      <Power>
         175
      </Power>
   </Engine>
</Car>

So if I need an engine power, I, followed by the best practices of business software development, will do the next thing:

Car car = dao.getCar()
Power power = car != null && car.engine != null ? power : null
return power

I hate this. Sometimes it seems that half of the code is just null checks.

Any ideas?

Take a look at Java 8 Optional class . It does exactly that: it avoids the ugly checks on null .

In your case, you could use this snippet of code to avoid them:

Car car = dao.getCar();
Optional<Car> optionalCar = Optional.ofNullable(car); 
Optional<Power> optionalPower = getPowerIfPresent(optionalCar);

Power power = Optional.empty();
if(optionalPower.isPresent()) {
    power = optionalPower.get();
}

after writing a function that returns the power of a given car :

public static Optional<Power> getPowerIfPresent(Optional<Car> car) {
    return car
        .flatMap(c -> c.getEngine())
        .map(e -> e.getPower());
}

This is the same as using of Optional , but might be more readable:

public class NullSafe<T> {
    private final T value;
    public NullSafe(@Nullable T value) { this.value = value; }
    public static <T> NullSafe<T> of(@Nullable T value) { return new NullSafe<>(value); }

    public <R> NullSafe<R> get(Function<T,R> mapper) {
        R newValue = (value != null) ? mapper.apply(value) : null;
        return new NullSafe<>(newValue);
    }

    public T nullable() { return value; }
    public T orDefault(T defaultValue) { return (value != null) ? value : defaultValue; }
}

And usage:

Power power = NullSafe.of(dao.getCar())
    .get(Car::getEngine)
    .get(Engine::getPower)
    .nullable(); // .orDefault(Power.defaultPower());

An alternative can be static methods:

public static <R> R get(Supplier<R> supplier, R defaultValue) {
    try {  return supplier.get(); } 
    catch (NullPointerException ex) { return defaultValue; }
}

public static <R> R getNullable(Supplier<R> supplier) { return get(supplier, null); }

And usage:

Power power = NullSafe.get(() -> dao.getCar().getEngine().getPower(), Power.defaultPower());
Power powerOrNull = NullSafe.getNullable(() -> dao.getCar().getEngine().getPower());

Or maybe create some util method:

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

Then you could use it like this:

System.out.println(tryGet(() -> car.engine.power).orElse(new Power()));

There is a library no-exception that does that, but you cannot specify it to only "silence" NPEs.

Exceptions.silence().get(() -> car.engine.power).orElse(new Power())

My own approach kind of this now:

public class CarDataExtractor {

   private final Car car;

   private CarDataExtractor(Car car) {
       this.car = car;
   }

  public static CarDataExtractor on(Car car) {
       return new CarDataExtractor(car);
   }

   public EngineDataExtractor engine() {
       return car != null && car.getEngine() != null
               ? EngineDataExtractor.on(car.getEngine())
               : EngineDataExtractor.on(null);
   }

   public Car self() {
       return car;
   }
}

public class EngineDataExtractor {

   private final Engine engine;

   private EngineDataExtractor(Engine engine) {
       this.engine = engine;
   }

   public static EngineDataExtractor on(Engine engine) {
       return new EngineDataExtractor(engine);
   }

   public PowerDataExtractor engine() {
       return engine != null && engine.getPower() != null
               ? PowerDataExtractor.on(engine.getPower())
               : PowerDataExtractor.on(null);
   }

   public Engine self() {
       return engine;
   }
}

...

Power power = CarDataExtractor.on(dao.getCar()).engine().power().self()

It is because I am restricted to Java 6...

There is also another option, you could use, which might be helpful for you if you're using Spring.

If you're not using Spring you would need to add additional dependency to your project.

Using Spel you could do:

ExpressionParser parser = new SpelExpressionParser();

StandardEvaluationContext context = new StandardEvaluationContext(dao.getCar());

Power power = parser.parseExpression("engine?.power").getValue(context, Power.class);

In expression engine?.power safe navigation operator is being used. In case engine is null , then the whole expression will evaluate to null .

This solution will work on Java 6.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM