aaron875499765
aaron875499765

Reputation: 31

Optional flatmap in Java has NullPointerException

Optional is used to avoid NullPointerException in Java 8.

But code has NullPointerException when I use Optional flatmap.

Code as below:

import java.util.Optional;
public class test2 {
  public static class Car {
    public Optional<Insurance> insurance;

    public Optional<Insurance> getInsurance() {
      return insurance;
    }
  }

  public static class Insurance {
    public String name;

    public String getName() {
      return name;
    }
  }

  public static class Person {
    public Optional<Car> car;

    public Optional<Car> getCar() {
      return car;
    }
  }
  public static String getCarInsuranceName(Optional<Person> person) {
    return person.flatMap(Person::getCar)
            .flatMap(Car::getInsurance)
            .map(Insurance::getName)
            .orElse("Unknown");
  }
  public static void main(String[] args) {
    Person person = new Person();
    Car car = new Car();
    Insurance insurance = new Insurance();
//    insurance.name = "test";
//    car.insurance = Optional.of(insurance);
    person.car = Optional.of(new Car());
    String result= getCarInsuranceName(Optional.of(person));
    System.out.println(result);
  }
}

Console information:

Exception in thread "main" java.lang.NullPointerException
    at java.util.Objects.requireNonNull(Objects.java:203)
    at java.util.Optional.flatMap(Optional.java:241)
    at test2.getCarInsuranceName(test2.java:29)
    at test2.main(test2.java:41)

person variable indeed has no insurance. But the result I want to get is Unknown, not NullPointerException.

Java version:

openjdk version "1.8.0_192"
OpenJDK Runtime Environment (AdoptOpenJDK)(build 1.8.0_192-b12)
OpenJDK 64-Bit Server VM (AdoptOpenJDK)(build 25.192-b12, mixed mode)

When person has insurance and insurance hasn't name, I got Unknown.

I want to know Why?

Upvotes: 1

Views: 3762

Answers (1)

Anonymous
Anonymous

Reputation: 86343

The insurance field of Car is always null. Never ever allow an Optional to be null, this defeats the whole idea of having an Optional. And will very often cause a surprising NullPointerException. This is what happens in your code too.

I suggest the following version of the Car class:

    public static class Car {
        private Insurance insurance = null;

        public Optional<Insurance> getInsurance() {
            return Optional.ofNullable(insurance);
        }
    }

It fixes the problem so the output now is:

Unknown

There’s no point (that I can see) in declaring insurance an Optional. It’s enough that your getter returns one. Optional is primarily for return values. It has few other good uses.

EDIT: @chrylis commented and doesn’t seem to like the combination of a plain reference field and a getter returning an Optional. I see nothing wrong with it, but if you prefer to keep your field an Optional as in the question, that’s certainly possible too. Then you just need to make sure that it isn’t null:

public static class Car {
    private Optional<Insurance> insurance = Optional.empty();

    public Optional<Insurance> getInsurance() {
        return insurance;
    }
}

This too fixes the program so we get the output above.

Whether a getter should be returning an Optional is discussed in this question: Should Java 8 getters return optional type? My first snippet above seems more to follow the recommendations in the least upvoted answer by Mark.

Upvotes: 1

Related Questions