I have a List<> of an Dto containing two parameters: type and value. Now I would like to find one element of the list with type “C” and read out the value.
When executing the following java code I get a NullPointerException which I do not understand:
class TestDto
{
private String type;
private Double value;
TestDto(final String type, final Double value)
{
this.type = type;
this.value = value;
}
public String getType() { return type; }
public Double getValue() { return value; }
}
…
List<TestDto> testList = new ArrayList<>();
testList.add(new TestDto("A", 11.111d));
testList.add(new TestDto("B", 22.222d));
testList.add(new TestDto("C", null));
Predicate<TestDto> typePredicate = c-> c.getType().equals("C");
Optional optional = testList.stream().filter(typePredicate).findFirst();
if(optional.isPresent()){
System.out.println("if-output = " + ((TestDto) optional.get()).getValue());
}
Double value = optional.isPresent() ? ((TestDto) optional.get()).getValue() : 0;
System.out.println(value);
The exception appears in the following line:
Double value = optional.isPresent() ? ((TestDto) optional.get()).getValue() : 0;
The value of the list element with type “C” is null, so I would expect the Double value to become null – which would be ok. This works inside of the if statement, it prints “if-output = null” as expected.
I would expect the if statement to be identical with the conditional operator. Do you have an idea why I get the NullPointerException?
Some remarks:
-
I have reduced the problem to the minimum. I do understand that there are easier ways to get the value of the Dto. I would just like to understand why the code shown above doesn’t work.
-
If you search for type “A” or “B” there is no error and the value is printed out twice
-
The replacement value “0” should be “0d” instead but it compiles with “0”. However when changing the code to:
Double value = optional.isPresent() ? null : 0;
it does not compile until I change the replacement value to “0d”. Maybe this helps to unserstand the problem.
Solution:
It’s a slightly funny one. Your ternary operator here:
optional.isPresent() ? ((TestDto) optional.get()).getValue() : 0;
is using a primitive zero. Java is deciding to first unbox your null Double to a primitive double, so that both results are of the same type, and that causes a NullPointerException.
If you replace 0 with Double.valueOf(0), both results of the ternary are of the type Double and so no unboxing needs to take place.
optional.isPresent() ? ((TestDto) optional.get()) : Double.valueOf(0);
As an aside, all of the horrible casting which makes your code look so ugly in places is a result of you not using the generic version of Optional. If you use generic version, your code could look like this:
Optional<TestDto> optional = testList.stream().filter(typePredicate).findFirst();
// ^ Generics!
if(optional.isPresent()){
System.out.println("if-output = " + optional.get().getValue());
}
Double value = optional.isPresent() ? optional.get().getValue() : Double.valueOf(0);
System.out.println(value);