Java Lambda for在两个for循环中中断

Java Lambda for在两个for循环中中断,java,collections,java-8,functional-programming,java-stream,Java,Collections,Java 8,Functional Programming,Java Stream,我正在尝试将Java8中的迭代代码块转换为函数式。功能方法无法在共享集中找到匹配的消息 List<Optional<Message>> allMessages = new ArrayList<>(); Set<Status> allStatuses = getAllStatuses(); //Iterative : Working Set<StatusMessage> set = new HashSet<>(STATUS

我正在尝试将Java8中的迭代代码块转换为函数式。功能方法无法在共享集中找到匹配的消息

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);
此外,出于调试目的,我如何看到流的每个步骤都发生了什么?intellij中调试器中的堆栈在流中没有显示任何内容。

这应该可以做到:

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());
List allMessages=STATUS\u MESSAGE.values().stream()
.distinct()
.flatMap(状态消息->
statusMessage.getStatusAndInfo().keySet().stream()
.map(状态->MessageBuilder.createMessage(所有状态,状态,此::createMessage))
.filter(可选::isPresent)
.限额(1)
)
.collect(Collectors.toList());
这应该可以做到:

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());
List allMessages=STATUS\u MESSAGE.values().stream()
.distinct()
.flatMap(状态消息->
statusMessage.getStatusAndInfo().keySet().stream()
.map(状态->MessageBuilder.createMessage(所有状态,状态,此::createMessage))
.filter(可选::isPresent)
.限额(1)
)
.collect(Collectors.toList());

这应该是一条注释,但太长了


似乎您的
MessageBuilder.createMessage
方法过于复杂

检查以下相同逻辑的简化和更可读版本:

if (allStatuses.contains(status)) {
    System.out.println("Found : " + status.toString());
    return creator.apply(status);
}
return Optional.empty();

这应该是一个评论,但是太长了


似乎您的
MessageBuilder.createMessage
方法过于复杂

检查以下相同逻辑的简化和更可读版本:

if (allStatuses.contains(status)) {
    System.out.println("Found : " + status.toString());
    return creator.apply(status);
}
return Optional.empty();

您不应该使用
forEach
进行累加操作,因此这应该更为惯用:

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());
Function messageForStatus=statusInfo->
statusInfo().keySet().stream()
.map(状态->MessageBuilder.createMessage(所有状态,状态,此::createMessage))
.filter(可选::isPresent)
.findFirst()
.orElse(可选.empty());
allMessages=STATUS_MESSAGE.values().stream()
.distinct()
.map(StatusMessage::getStatusAndInfo)
.map(messageForStatus)
.filter(可选::isPresent)
.collect(toList());

作为一个旁注,你有太多的选择,你可能想考虑一些更早的解包,因为一个选择列表也可能只是当前值的列表。

不应该使用<代码>前缀来积累操作,所以这应该更习惯:

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());
Function messageForStatus=statusInfo->
statusInfo().keySet().stream()
.map(状态->MessageBuilder.createMessage(所有状态,状态,此::createMessage))
.filter(可选::isPresent)
.findFirst()
.orElse(可选.empty());
allMessages=STATUS_MESSAGE.values().stream()
.distinct()
.map(StatusMessage::getStatusAndInfo)
.map(messageForStatus)
.filter(可选::isPresent)
.collect(toList());

作为一个旁注,您有太多的选择,您可能需要考虑提前解包,因为OpTIONS的列表也可能是当前值的列表。

<代码>任意匹配期望谓词并返回布尔值。你可能想要
.filter()
然后只
.collect
你说的“不工作”是什么意思?请详细说明
.anyMatch(allMessages::add)将在成功添加后立即停止,这将在第一次迭代时发生。改为使用
findFirst
(如果顺序不相关,则使用findAny,然后写入
allMessages=…stream()…flatMap()…filter(可选::isPresent).findFirst()或lse(emptyList())
@njzk2但是
中断
仅用于内部循环,您仍应继续使用外部循环…然后重新运行内部循环。因此,每个外部循环最多一个项目.STATUS\u消息是一个映射。我使用的命名肯定可以改进。
anyMatch
需要一个谓词并返回一个布尔值。您可能需要
.filter()
,然后只需
。collect
您所说的“不工作”是什么意思?请详细说明
。anyMatch(allMessages::add);
将在成功添加后立即停止,这将在第一次迭代时发生。请改用
findFirst
(如果顺序不相关,则使用findAny,然后写入
allMessages=…stream()…flatMap()…filter(可选::isPresent).findFirst().orElse(emptyList())
@njzk2但是
中断
仅用于内部循环,您仍应继续使用外部循环…然后重新运行内部循环。因此,每个外部循环最多一个项目.STATUS_消息是一张地图。我使用的命名肯定可以改进。我优化并移动了两个对象初始化,但从未意识到这有多简单。感谢@ETOI注释,我优化并移动了两个对象初始化,从未意识到这有多简单。感谢不应使用@etofeach注释将内容添加到列表中。这就是collect的用途(即使在这种情况下,它意味着在地图中要稍微复杂一些。)middle@njzk2添加了解决方案。很好地使用了
limit
,我没有想到在这种情况下使用它。不应使用foreach将内容添加到列表中。这就是collect的用途(即使在这种情况下,它意味着在地图中要稍微复杂一些。)middle@njzk2添加了解决方案。很好地使用了
限制
,我没有想到在这种情况下使用它