findFirst抛出java.lang.NullPointerException

fas*_*ava 5 java optional java-8 java-stream

我在下面有这个代码.该findfirst呼叫被抛出NullPointerException,虽然我有一个甚至orElseGet调用链

int numberOfRetry = 5;
String req = "abc";
String res =
    Stream.iterate(0, n -> n + 1).map(i -> {
        try {
            return req.substring(numberOfRetry - i);
        } catch (Exception e) {
            // log exception
        }
        return null;
    })
    .limit(1)
    .findFirst()
    .orElseGet(() -> "Exception");
Run Code Online (Sandbox Code Playgroud)

但是,如果我进行过滤器调用,它可以正常工作,如下所示:

int numberOfRetry = 5;
String req = "abc";
String res =
    Stream.iterate(0, n -> n + 1).map(i -> {
        try {
            return req.substring(numberOfRetry - i);
        } catch (Exception e) {
            // log exception
        }
        return null;
    })
    .limit(1)
    .filter(Objects::nonNull)
    .findFirst()
    .orElseGet(() -> "Exception");
Run Code Online (Sandbox Code Playgroud)

我想我们null在某些情况下无法明确返回,而且乍一看这些情况并不十分清楚.在第一种情况下,它返回一个stream带有null抛出的元素NullPointerException,在第二种情况下,它返回一个工作正常的空流.

Nam*_*man 6

您的代码明确返回 null

return null
Run Code Online (Sandbox Code Playgroud)

其后抛出NPE,根据其规格 Optional.findFirst读取:

@throws NullPointerException if the element selected is null
Optional<T> findFirst();
Run Code Online (Sandbox Code Playgroud)

此外,澄清代码控制甚至无法到达orElseGet无论如何假设适用于Optional(空或具有某些值)的部分.


几点建议:

  • 不要忽略异常,特别是当你从中捕获到最常见的异常时.
  • 避免null在迭代中明确返回,这似乎与你为什么要迭代相矛盾.
  • 当前代码中更安全的一面,您可以使用filteras 过滤非nonNull对象

    Stream.iterate(0, n -> n + 1).map(i -> {
           try {
               return req.substring(numberOfRetry - i);
           } catch (Exception e) {
               err.add(e);
           }
           return null;
    })
    .filter(Objects::nonNull)
    .limit(1)
    .findFirst()
    .orElse("Exception");
    
    Run Code Online (Sandbox Code Playgroud)