Поиск непустого списка внутри списка с использованием функций Java 8 - PullRequest
0 голосов
/ 19 января 2019

У меня есть фрагмент кода, который я хочу сделать более кратким, но читабельным использование функций Java 8, таких как лямбда / потоки и т. д.

В основном, есть список элементов, и у каждого элемента есть список ошибок. Если есть хотя бы один элемент с хотя бы одной ошибкой, необходимо вернуть «сбой». Если нет элементов с какой-либо ошибкой, вернуть «success».

Optional<List<Item>> optionalItemList = Optional.ofNullable(message.getItems());

if (optionalItemList.isPresent())
    for (Item item : optionalItemList.get()) {
        Optional<List<Error>> optionalErrorList = Optional.ofNullable((item.getErrors()));
        if(optionalErrorList.isPresent())
            if (!optionalErrorList.get().isEmpty()) {
                return "failure";
            }
        }
        return "success";

Ответы [ 4 ]

0 голосов
/ 19 января 2019

Вы можете использовать flatMap для поиска в списке.Я лично считаю, что List должно никогда быть null, вместо этого это должен быть пустой список.Если это гарантия, тогда код может быть таким:

boolean hasError = message.getItems().stream()
    .flatMap(t -> t.getErrors().stream())
    .findAny()
    .isPresent();
return (hasError ? "success" : "failure");

В противном случае код становится немного длиннее:

boolean hasError = Optional.ofNullable(message.getItems()).orElse(List.of()).stream()
    .flatMap(t -> Optional.ofNullable(t.getErrors()).orElse(List.of()).stream())
    .findAny()
    .isPresent();
return (hasError ? "success" : "failure");

Обратите внимание, что я мог бы также использовать .count() > 0.findAny().isPresent().Но недостаток первого состоит в том, что он повторяется по всем ошибкам, а последний - при коротком замыкании, если обнаружена какая-либо ошибка.

0 голосов
/ 19 января 2019

Для меня вы сделали это слишком сложным. Вот гораздо более простой способ сделать это. Убедитесь, что ваш метод getItems() возвращает пустой список, если нет элементов для возврата, чтобы вы могли обойтись без дополнительных нулевых проверок, как указано выше. Этот подход менее подвержен ошибкам и приводит к более читаемому коду. Если вы можете сделать то же самое для метода getErrors, описанного выше, вы можете просто отказаться от filter(Objects::nonNull), и это еще больше упростит конвейер потоковой обработки.

String errorPresent = message.getItems().stream()
    .map(Item::getErrors).filter(Objects::nonNull)
    .map(List::size).filter(s -> s > 0)
    .findAny().map(ignored -> "failure")
    .orElse("success");

В качестве альтернативы вы можете использовать троичный оператор, чтобы выполнить эту задачу.

String errorPresent = message.getItems().stream()
    .map(Item::getErrors)
    .filter(Objects::nonNull)
    .anyMatch(e -> !e.isEmpty()) ? "failure" : "success";
0 голосов
/ 19 января 2019

Optional не предназначен для замены if операторов, но должен использоваться в качестве возвращаемого значения методов.Поэтому я думаю, что вам лучше не использовать его для этой задачи.Вместо этого вы можете использовать троичный оператор вместе с Stream.allMatch:

return message.getItems() == null || 
       message.getItems().stream()
              .allMatch(i -> i.getErrors() == null || i.getErrors().isEmpty()) ?
      "success" :
      "failure";

На заметку о том, что методы никогда не должны возвращать null наборов.Отсутствие элементов должно выражаться в возврате пустых коллекций.Это сделало бы ваш код намного проще:

return message.getItems().stream().allMatch(i -> i.getErrors().isEmpty()) ?
      "success" :
      "failure";
0 голосов
/ 19 января 2019

Вы можете использовать anyMatch для итеративного кода как:

Optional<List<Item>> optionalItemList = Optional.ofNullable(message.getItems());
if (optionalItemList.isPresent())
    if (optionalItemList.get().stream()
            .map(item -> Optional.ofNullable((item.getErrors())))
            .filter(Optional::isPresent)
            .anyMatch(optionalErrorList -> !optionalErrorList.get().isEmpty())) {
        return "failure";
    }
return "success";

или еще более упростить его как:

return Optional.ofNullable(message.getItems())
        .filter(a -> a.stream()
                .map(item -> Optional.ofNullable((item.getErrors())))
                .filter(Optional::isPresent)
                .anyMatch(optionalErrorList -> !optionalErrorList.get().isEmpty()))
        .map(a -> "failure")
        .orElse("success");
...