为什么 findFirst() 会抛出一个 NullPointerException,如果它找到的第一个元素是 null?

2022-08-31 09:01:24

为什么这会抛出一个 ?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

中的第一项是 ,这是一个完全可以接受的值。此外,返回一个 Optional,这对于能够处理 s 更有意义。stringsnullfindFirst()findFirst()null

编辑:更新了,以减少歧义。orElse()


答案 1

其原因是使用在返回。不允许包含 可选。从本质上讲,它没有提供区分情况的方法“它不在那里”和“它在那里,但它被设置为”。Optional<T>nullnull

这就是为什么文档明确禁止在 以下位置中选择的情况:nullfindFirst()

抛出:

NullPointerException- 如果所选元素是null


答案 2

如前所述,API 设计人员并不认为开发人员希望以相同的方式处理值和缺少的值。null

如果您仍然想这样做,则可以通过应用序列来显式执行此操作

.map(Optional::ofNullable).findFirst().flatMap(Function.identity())

到流。在这两种情况下,如果没有第一个元素或第一个元素是 .,则结果都将是空的可选项。因此,在您的情况下,您可以使用null

String firstString = strings.stream()
    .map(Optional::ofNullable).findFirst().flatMap(Function.identity())
    .orElse(null);

在第一个元素不存在或 .nullnull

如果要区分这些情况,可以直接省略以下步骤: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"));

这与更新后的问题没有太大区别。您只需要用 和 替换 。但是如果你不喜欢条件,你也可以像这样实现它:"no such element""StringWhenListIsEmpty""first element is null"null

String firstString = strings.stream().skip(0)
    .map(Optional::ofNullable).findFirst()
    .orElseGet(()->Optional.of("StringWhenListIsEmpty"))
    .orElse(null);

现在,如果一个元素存在,但存在,并且当没有元素存在时,它将是。firstStringnullnull"StringWhenListIsEmpty"


推荐