假设你有一个包含空值的整数列表
List<Integer> integers = Arrays.asList(null, 9, 11, 7, 5, null);
现在,如果您想获得最大值,可以尝试
OptionalInt max = integers.stream()
.mapToInt(Integer::valueOf)
.max();
如果列表不包含空值,这将起作用。在我们的例子中,将有一个NullPointerException。经过一些研究,我可以看到这样的解决方案
Optional<Integer> max = integers.stream()
.max(Comparator.nullsFirst(Comparator.naturalOrder()));
如果您认为空值小于非空值,则它有效。但是,如果您希望它们更大并将nullsFirst更改为nullsLast
Optional<Integer> max = integers.stream()
.max(Comparator.nullsLast(Comparator.naturalOrder()));
那么你将再次遇到NullPointerException。
我很感兴趣 - 考虑到它的文档声明它是空友好的,为什么 nullsLast 在这种情况下不起作用? 对包含空值的整数列表进行排序的最佳方法是什么?
感谢您的想法!
这与Comparator
本身无关:
List<Integer> result = integers.stream()
.sorted(Comparator.nullsLast(Comparator.naturalOrder()))
.collect(Collectors.toList());
System.out.println(result); // [5, 7, 9, 11, null, null]
你把你的空值放在最后,那将是max
;在空上调用max
抛出该NullPointerException
。
Stream#max
的文档指出:
抛出:空指针异常 - 如果最大元素为空
由于您提供了一个比较器,它将null
视为最大元素,因此这就是它引发异常的原因。
这是堆栈跟踪在示例中null
尝试返回state
Optional.of(state);
时指示的内容,如果传递的值null
,则Optional.of
抛出 NPE。
Comparator.nullsLast
工作正常,例如:
Integer max =
Collections.max(integers, Comparator.nullsLast(Comparator.naturalOrder()));
确实会给你null
.
如果您认为null
大于任何非null
值,那么当列表包含任何null
时,最大值当然会null
。
由于Stream.max
已经记录了当结果null
时它将抛出NullPointerException
,这是预期的行为。设计原理类似于findFirst()
,这在本次问答中已经讨论过。
请注意,即使
Optional<Integer> max = integers.stream()
.max(Comparator.nullsFirst(Comparator.naturalOrder()));
仍然可以失败,即如果所有值都null
.但是在这里使用自定义Comparator
是没有意义的,因为解决方案很简单:
OptionalInt max = integers.stream()
.filter(Objects::nonNull)
.mapToInt(Integer::valueOf)
.max();
当你得到一个空的OptionalInt
时,你仍然可以测试integers.isEmpty()
以确定是所有元素都null
还是根本没有元素。