Reputation: 31
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
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