Java 8流-如何正确制作NPE安全流

时间:2018-10-29 07:50:55

标签: java java-stream

上周在流中出现了非常奇怪的NPE,这引起了我的很多麻烦,所以现在我感觉使用NPE时使用NPE过于安全。

这是我现在的方法:

private boolean matchSomeError(final List<ErrorAtMessageLevel> errorList) {
    return errorList.stream()
        .filter(errorAtMessageLevel -> errorAtMessageLevel.getErrorSegment() != null && errorAtMessageLevel.getErrorSegment().getErrorDetails() != null)
        .map(errorAtMessageLevel -> errorAtMessageLevel.getErrorSegment().getErrorDetails())
        .anyMatch(errorDetails -> SOME_FANCY_ERROR_CODE.equals(errorDetails.getErrorCode()));
}

我的问题是我在这里处理外部POJO,所以我无法更改它并使它为null安全,因此必须调整代码。

以下是一些限制: 1)errorList-此处不能为null,因此对.stream()的调用是安全的-当它为空时,它只会返回false 2)getErrorSegment()getErrorDetails()都可以为空,这就是为什么我使用类似的过滤器以确保它们都不为空的原因 3)getErrorCode()可以为null,但是它永远不会抛出NPE,因为与null匹配时它只会返回false-我可以。

您将如何改善该流?我觉得自己的.filter()不好,可以做得更好。最近写了很多这样的代码,因为我不确定该流如何处理空值,并且不想在.map()中获得NPE,因为它被调用为空值

2 个答案:

答案 0 :(得分:8)

您可以通过以下方式更优雅地过滤null

private boolean matchSomeError(final List<ErrorAtMessageLevel> errorList) {
    return errorList.stream()
        .map(ErrorAtMessageLevel::getErrorSegment)
        .filter(Objects:nonNull)
        .map(ErrorSegment::getErrorDetails)
        .filter(Objects:nonNull)
        .anyMatch(errorDetails -> SOME_FANCY_ERROR_CODE.equals(errorDetails.getErrorCode()));
}

答案 1 :(得分:2)

我认为写此代码的最好方法是定义一个单独的方法,该方法使用Optional来避免空值。然后,您可以在流中使用方法引用来引用它:

return errorList.stream()
    .map(MyClass::getErrorCode)
    .flatMap(Optional::stream) // from Java 9, else filter then map to Optional.get
    .anyMatch(SOME_FANCY_ERROR_CODE::equals);


private static Optional<String> getErrorCode(final ErrorAtMessageLevel error)
{
    return Optional.ofNullable(error)
        .map(ErrorAtMessageLevel::getErrorSegment)
        .map(ErrorSegment::getErrorDetails)
        .map(ErrorDetails::getErrorCode);
}

您的类名可能与方法引用不同。您的代码没有显示使用了什么类,所以我只是使用了合理的猜测。