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