1

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?

  • I suspect he just simply needed something like .findAny().orElse("Unknown")? I don't think .orElse on its own would finalize the stream the way he intended? – djangofan Dec 08 '18 at 04:37
  • Reopened because this question is more about the intricacies of using an `Optional` chain, and the most correct answer (use the chain in a different manner) differs substantially from the canonical NPE question. – chrylis -cautiouslyoptimistic- Dec 08 '18 at 05:21
  • This is from `Modern Java in Action` ? – Koray Tugay Dec 25 '18 at 15:47

1 Answers1

1

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.

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
  • Instead, use the standard JavaBean idiom and return `null` from `Insurance getInsurance()`. Using `map` instead of `flatMap` Does The Right Thing. – chrylis -cautiouslyoptimistic- Dec 08 '18 at 05:22
  • So you’re objecting to using `Optional` at all in the first place? That’s a valid opinion too. More discussion here: [Should Java 8 getters return optional type?](https://stackoverflow.com/questions/26327957/should-java-8-getters-return-optional-type) – Ole V.V. Dec 08 '18 at 05:31
  • Not objecting to using `Optional` *entirely*, but it's not idiomatic to use it here, especially when the backing field for the property is a plain reference. – chrylis -cautiouslyoptimistic- Dec 08 '18 at 06:26
  • Thanks for your opinion, @chrylis. I have edited (still with respect for the asker’s way of doing things). – Ole V.V. Dec 08 '18 at 09:08