6

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?

7
  • That's the design of your XML... Commented Sep 8, 2017 at 11:33
  • I'm going to flag this as "unclear what you are asking." Commented Sep 8, 2017 at 11:36
  • 4
    potentially, any of these nodes is not present. You can check your xml file against a xsd schema, otherwise you have to do the checks manually. Commented Sep 8, 2017 at 11:36
  • 1
    @HeikkiMäenpää why is this unclear? The question is about how to eliminate boilerplate code. Commented Sep 8, 2017 at 11:37
  • 2
    Is that valid for a car to not have an engine? Is that valid for an engine to not have a power? If not, then you should not do these null-checks, because the values should never be null, and if they are, you'd better fail early to make the bug obviously apparent, rather than returning null and clutter your code. Commented Sep 8, 2017 at 11:45

5 Answers 5

7

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());
}
Sign up to request clarification or add additional context in comments.

2 Comments

Interesting approach, thanks! But it does not seem to be generic enough. I mean, I still need to create a lot of methods: getPowerIfPresent, getColorIfPresent, getEngineLeftPanelNumberOfBoltsIfPresent ...
No problem, it's just that your question didn't state this very explicitly in the first place or I might have over-simplified it.
2

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

1 Comment

Thank you! I've build the same thing in my project, but without any generic, unfortunately. As I have Java 6 restriction.
1

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...

2 Comments

I think you're over-engineering this. Just write simple method 'extractPower', which would encapsulate null-checks and this should be enough.
It is not just about the engine power. In my project there is an a great entity built from XML. And there are hundreds of duplicates with null-checks around the code
1

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

1 Comment

Great! Thank you, Sir! This is exactly the answer I've been trying to find!
1

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.

2 Comments

Thank you! I've never heard about Spell before. But I afraid it can add a significant overhead to the performance, through for some use cases I think its usage is pretty helpful
Please have a look at this section: SpEL compilation

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.