Поток Java 8 - как правильно сделать NPE-безопасный поток - PullRequest
0 голосов
/ 29 октября 2018

На прошлой неделе в потоке появился очень странный NPE, что вызвало у меня массу неприятностей, поэтому сейчас я чувствую себя слишком защищенным с NPE при использовании Stream.

Вот мой метод прямо сейчас:

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, поэтому я не могу изменить его и сделать его безопасным, так что мне нужно настроить свой код.

Вот некоторые ограничения: 1) errorList - здесь не может быть null, поэтому вызов .stream() безопасен - когда он пуст, он просто возвращает false 2) getErrorSegment() и getErrorDetails() могут быть равны нулю, поэтому я использую такой фильтр, чтобы убедиться, что ни один из них не равен нулю 3) getErrorCode() может быть нулевым, но он никогда не сгенерирует NPE, потому что он просто вернет false при сопоставлении с нулем - отлично для меня.

Как бы вы сделали этот поток лучше? Я чувствую, что мой .filter() плох, и это можно сделать лучше. В последнее время пишу много такого кода, потому что я больше не уверен, как поток работает с нулями, и не хочу получать NPE в .map(), потому что он вызывается для нуля

Ответы [ 2 ]

0 голосов
/ 29 октября 2018

Я думаю, что лучший способ написать это - определить отдельный метод, который использует 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);
}

Ваши имена классов могут быть разными для ссылок на методы. Ваш код не показывает, какие классы использовались, поэтому я просто использовал разумные догадки.

0 голосов
/ 29 октября 2018

Вы можете отфильтровать 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()));
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...