Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Optional in Java conditional operator leads to NullPointerException

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.

like image 852
mgerbracht Avatar asked Dec 13 '22 18:12

mgerbracht


1 Answers

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);
like image 199
Michael Avatar answered Dec 17 '22 23:12

Michael