Java лямбда для разрыва внутри двух для петель - PullRequest
1 голос
/ 31 марта 2020

Я пытаюсь преобразовать итеративный блок кода в Java 8 в функциональный. Функциональный подход не может найти соответствующее сообщение в общем наборе.

List<Optional<Message>> allMessages = new ArrayList<>();

Set<Status> allStatuses = getAllStatuses();

//Iterative : Working
Set<StatusMessage> set = new HashSet<>(STATUS_MESSAGE.values());
for (StatusMessage statusMessage : set) {
    for (Status status : statusMessage.getStatusAndInfo().keySet()) {
        Optional<Message> message = MessageBuilder.createMessage(allStatuses, status, this::createMessage);
        if (message.isPresent()) {
            allMessages.add(message);
            break;
        }
    }
}

//Functional : Not working  - Never adds anything to the 
//map even when matching status is present
STATUS_MESSAGE.values().stream()
        .distinct()
        .map(statusMessage -> statusMessage.getStatusAndInfo().keySet())
        .flatMap(Collection::stream)
        .map(key -> MessageBuilder.createMessage(allStatuses, key, this::createMessage))
        .anyMatch(allMessages::add);

MessageBuilder.createMessage выглядит следующим образом:

Optional<Status> matchingStatus = statuses.stream()
                .filter(matchingStatus::equals)
                .findFirst();
System.out.println("Found : " + matchingStatus.toString());
return matchingStatus.flatMap(creator);

Кроме того, как в целях отладки, как я могу видите, что происходит на каждом шагу потока? Стек в отладчике в intellij ничего не показывает в потоке.

Ответы [ 3 ]

5 голосов
/ 31 марта 2020

Это должно сделать это:

STATUS_MESSAGE.values().stream()
        .distinct()
        .forEach(statusMessage ->
            statusMessage.getStatusAndInfo().keySet().stream()
                    .map(status -> MessageBuilder.createMessage(allStatuses, status, this::createMessage))
                    .filter(Optional::isPresent)
                    .findFirst()
                    .ifPresent(allMessages::add)
        );

ОБНОВЛЕНИЕ

Чтобы построить список результатов, используя toList вместо добавления в список:

List<Optional<Message>> allMessages = STATUS_MESSAGE.values().stream()
        .distinct()
        .flatMap(statusMessage ->
            statusMessage.getStatusAndInfo().keySet().stream()
                    .map(status -> MessageBuilder.createMessage(allStatuses, status, this::createMessage))
                    .filter(Optional::isPresent)
                    .limit(1)
        )
        .collect(Collectors.toList());
2 голосов
/ 31 марта 2020

Это должен быть комментарий, но он слишком длинный ...


Похоже, ваш MessageBuilder.createMessage метод слишком сложен.

Проверьте ниже упрощенную и более читаемую версию тот же лог c:

if (allStatuses.contains(status)) {
    System.out.println("Found : " + status.toString());
    return creator.apply(status);
}
return Optional.empty();
0 голосов
/ 01 апреля 2020

Вы не должны использовать forEach для накопления операций, так что это должно быть более идиоматическим c:

Function<StatusInfo, Optional<Message>> messageForStatus = statusInfo -> 
        statusInfo().keySet().stream()
                    .map(status -> MessageBuilder.createMessage(allStatuses, status, this::createMessage))
                    .filter(Optional::isPresent)
                    .findFirst()
                    .orElse(Optional.empty());

allMessages = STATUS_MESSAGE.values().stream()
        .distinct()
        .map(StatusMessage::getStatusAndInfo)
        .map(messageForStatus)
        .filter(Optional::isPresent)
        .collect(toList());

В качестве примечания, у вас слишком много опций, вы можете рассмотреть возможность разворачивания некоторые ранее, так как список опциональных символов может быть также списком только текущих значений.

...