为什么findFirst()如果find的第一个元素为null,会抛出NullPointerExceptionexception?
为什么这会抛出一个java.lang.NullPointerException
?
List<String> strings = new ArrayList<>(); strings.add(null); strings.add("test"); String firstString = strings.stream() .findFirst() // Exception thrown here .orElse("StringWhenListIsEmpty"); //.orElse(null); // Changing the `orElse()` to avoid ambiguity
strings
的第一项是null
,这是一个完全可以接受的值。 此外, findFirst()
返回一个Optional ,这对于findFirst()
能够处理null
来说更为findFirst()
。
编辑:更新orElse()
更不明确。
原因是在返回中使用了Optional<T>
。 可选不允许包含null
。 从本质上讲,它没有办法区分“不在那里”和“在那里,但它被设置为null
”的情况。
这就是为什么当在findFirst()
selectnull
时,文档明确禁止这种情况:
抛出:
NullPointerException
– 如果select的元素为null
如前所述,APIdevise者不会假设开发者想要以相同的方式处理null
值和缺失值。
如果你仍然想这样做,你可以通过应用序列明确地做到这一点
.map(Optional::ofNullable).findFirst().flatMap(Function.identity())
到stream。 如果没有第一个元素,或者第一个元素为null
,则结果在两种情况下都是可选的。 所以在你的情况下,你可以使用
String firstString = strings.stream() .map(Optional::ofNullable).findFirst().flatMap(Function.identity()) .orElse(null);
如果第一个元素不存在或为null
。
如果您想区分这些情况,您可以简单地省略flatMap
步骤:
Optional<String> firstString = strings.stream() .map(Optional::ofNullable).findFirst().orElse(null); System.out.println(firstString==null? "no such element": firstString.orElse("first element is null"));
这与您更新的问题没有多大区别。 你只需用"StringWhenListIsEmpty"
和"first element is null"
replace为"no such element"
。 但是,如果你不喜欢条件,你可以实现它也像:
String firstString = strings.stream().skip(0) .map(Optional::ofNullable).findFirst() .orElseGet(()->Optional.of("StringWhenListIsEmpty")) .orElse(null);
现在,如果元素存在,则firstString
将为null
,但为null
,如果元素不存在,则为"StringWhenListIsEmpty"
。
以下代码用limit(1)
replacefindFirst()
,并用orElse()
replaceorElse()
reduce()
:
String firstString = strings. stream(). limit(1). reduce("StringWhenListIsEmpty", (first, second) -> second);
limit()
只允许1个元素达到reduce
。 传递的BinaryOperator
reduce
返回1个元素,否则返回"StringWhenListIsEmpty"
如果没有元素到达reduce
。
这个解决scheme的BinaryOperator
是Optional
不分配和BinaryOperator
lambda不会分配任何东西。
您可以使用java.util.Objects.nonNull在查找之前过滤列表
就像是
list.stream().filter(Objects::nonNull).findFirst();
可选应该是一个“价值”types。 (请阅读javadoc中的细则 🙂 JVM甚至可以用Optional<Foo>
replace所有Optional<Foo>
,从而消除所有装箱和拆箱成本。 null
Foo表示一个空的Optional<Foo>
。
这是一个可能的devise,允许可选的空值,而不添加布尔标志 – 只需添加一个哨兵对象。 (甚至可以用this
作为标记;参见Throwable.cause)
可选不能包含null的决定不是基于运行时成本。 这是一个非常有争议的问题,你需要挖掘邮件列表。 这个决定对每个人都没有说服力。
在任何情况下,由于Optional不能包装null值,所以它findFirst
这样的情况推到一个angular落。 他们必须推断null值非常罕见(甚至认为Stream应禁止空值),因此在null值而不是空值上抛出exception更为方便。
一个解决方法是框为null
,例如
class Box<T> static Box<T> of(T value){ .. } Optional<Box<String>> first = stream.map(Box::of).findFirst();
(他们说,每个OOP问题的解决scheme是引入另一种types:)