Bogdan
Bogdan

Reputation: 320

Java 8 - Sort list of integers with nulls

Lets say you have a list of integers containing null vaues

List<Integer> integers = Arrays.asList(null, 9, 11, 7, 5, null);

Now if you want to get max value, you can try

OptionalInt max = integers.stream()
        .mapToInt(Integer::valueOf)
        .max();

This would work if the list did not contain nulls. In our case there will be a NullPointerException. After some research I can see such solution

Optional<Integer> max = integers.stream()
        .max(Comparator.nullsFirst(Comparator.naturalOrder()));

It works if you consider nulls less then non-nulls. But if you want them to be greater and change nullsFirst to nullsLast

Optional<Integer> max = integers.stream()
        .max(Comparator.nullsLast(Comparator.naturalOrder()));

then you will meet NullPointerException again.

I am interesting - why nullsLast doesn't work in this case considering that its doc states that it is null-friendly? And what is the best way to sort list of Integers containing nulls?

Thanks for your ideas!

Upvotes: 3

Views: 8201

Answers (3)

Holger
Holger

Reputation: 298539

If you consider null to be larger than any non-null value, the maximum will be, of course, null when list contains any null.

Since Stream.max already documents that it will throw a NullPointerException when the result is null, this is expected behavior. The design rationale is similar to findFirst(), which has been discussed in this Q&A.

Note that even

Optional<Integer> max = integers.stream()
    .max(Comparator.nullsFirst(Comparator.naturalOrder()));

can still fail, i.e. if all values are null. But there is no point in using a custom Comparator here, as the solution is straight-forward:

OptionalInt max = integers.stream()
    .filter(Objects::nonNull)
    .mapToInt(Integer::valueOf)
    .max();

When you get an empty OptionalInt, you may still test integers.isEmpty() to determine whether all elements were null or there were no elements at all.

Upvotes: 2

Alexis C.
Alexis C.

Reputation: 93872

The documentation of Stream#max states:

Throws: NullPointerException - if the maximum element is null

As you provided a comparator that will consider null as a maximum element, then that is why it throws the exception.

This is what the stacktrace indicates when it tries to return Optional.of(state); with state being null in your example, and Optional.of throws a NPE if the value being passed is null.

Comparator.nullsLast works fine, for example:

Integer max = 
    Collections.max(integers, Comparator.nullsLast(Comparator.naturalOrder()));

will indeed give you null.

Upvotes: 3

Eugene
Eugene

Reputation: 121008

That's not about Comparator per-se:

List<Integer> result = integers.stream()
            .sorted(Comparator.nullsLast(Comparator.naturalOrder()))
            .collect(Collectors.toList());
System.out.println(result); // [5, 7, 9, 11, null, null]

You are putting your nulls to the end and that would be max; calling max on a null throws that NullPointerException.

Upvotes: 4

Related Questions