如何使用Java8流和Lambdas迭代引用父元素的嵌套for循环?

如何使用Java8流和Lambdas迭代引用父元素的嵌套for循环?,lambda,java-8,java-stream,Lambda,Java 8,Java Stream,我有下面的代码 public static ModuleKey getDeployableModuleFromModulesList(List<Module> modules) { ModuleKey deployableModuleKey = null; for(Module module : modules) { List<Artifact> artifacts = module.getArtifacts();

我有下面的代码

public static ModuleKey getDeployableModuleFromModulesList(List<Module> modules) {
        ModuleKey deployableModuleKey = null;
        for(Module module : modules) {
            List<Artifact> artifacts = module.getArtifacts();
            for(Artifact artifact : artifacts) {
                if(artifact.getType().equals("ear")) {
                    return module.getKey();
                } else if(!artifact.getType().equals("ear")) {
                    if(artifact.getType().equals("war")) {
                        deployableModuleKey = module.getKey();
                    } 
                }
            }
        }
        return deployableModuleKey;
    }
上面的代码片段将返回类型为
工件
的对象,而不是
模块
。我想获得工件符合条件的模块。找到模块后,我可以通过执行
module.getKey()
返回密钥。 为此,我想知道如何引用循环的父元素

我不确定我的Java 8代码是否完全正确。

有人能在这方面帮助我吗?

流的问题是,一旦您使用中间操作(如
filter
map
)修改了流,您就不能引用上一个操作的值。因此,您必须找到解决方法,以便始终保持(在您的情况下,
模块
)您希望在流中引用的值。在下面的解决方案中,我使用
anyMatch
操作打开了两个二级流,如果模块包含包含所需密钥的工件,则会给出一个正值

这应该可以做到:

ModuleKey key = Optional.ofNullable(modules.stream().filter(m -> m.getArtifacts().stream()
    .anyMatch(a -> a.equals("ear"))).findFirst().orElse(modules.stream()
    .filter(m -> m.getArtifacts().stream().anyMatch(a -> a.equals("war")))
    .reduce((a, b) -> b).orElse(null))).map(Module::getKey).orElse(null);
要查找第一个元素,请使用
findFirst
,它返回一个
可选的
。我们将
Optional
链接到
Optional#orElse
,它将打开它,如果它为空,则返回另一个值(在本例中,使用
reduce((a,b)->b)
查找最后一个元素)。如果没有找到任何内容,我们不希望代码抛出
NullPointerException
。因此,在调用
getKey
方法之前,我们使用
Optional.ofNullable
将所有这些内容包装成一个
Optional
,并将
orElse
设置为
null
,这是代码中指定的默认值

作为旁注

else if(!artifact.getType().equals("ear")) {
    if(artifact.getType().equals("war")) {
    }
}
可以简化为

else if(artifact.getType.equals("war")) {
}

我想您已经意识到冗余的
if
检查您的旧Java风格代码

我已经通过分解成每个人都能理解的较小的简单函数,编写了您的大型单一操作流

public static ModuleKey getDeployableModuleFromModulesList(List<Module> modules) {

    return findEARKey(modules.stream())
            .orElse(findWARKey(modules.stream()).orElse(null));

}

public static Optional<ModuleKey> findEARKey(Stream<Module> moduleStream){

    return  moduleStream.flatMap(e -> e.getArtifacts().stream())
            .filter(e -> e.getType().equals("ear"))
            .map(Artifact::getKey).findFirst();
}

public static Optional<ModuleKey> findWARKey(Stream<Module> moduleStream){

    return  moduleStream.flatMap(e -> e.getArtifacts().stream())
            .filter(e -> e.getType().equals("war"))
            .map(Artifact::getKey).findFirst();
}
公共静态模块key getDeployableModuleFrommoduleList(列出模块){
返回findEARKey(modules.stream())
.orElse(findWARKey(modules.stream()).orElse(null));
}
公共静态可选findEARKey(流模块Stream){
返回moduleStream.flatMap(e->e.getArtifacts().stream())
.filter(e->e.getType().equals(“ear”))
.map(工件::getKey).findFirst();
}
公共静态可选密钥(流模块Stream){
返回moduleStream.flatMap(e->e.getArtifacts().stream())
.filter(e->e.getType().equals(“war”))
.map(工件::getKey).findFirst();
}

我已经想出了解决问题的办法

public static ModuleKey getDeployableModuleFromModulesList(List<Module> modules) {
    Optional<ModuleKey> op = modules.stream().filter(module -> module.getArtifacts().stream().anyMatch(artifact -> artifact.getType().equals("ear"))).map(module -> module.getKey()).findFirst();
    if (!op.isPresent()) {
        op = modules.stream().filter(module -> module.getArtifacts().stream().anyMatch(artifact -> artifact.getType().equals("war"))).map(module -> module.getKey()).reduce((a, b) -> b);
    }
    return op.orElse(null);
}
公共静态模块key getDeployableModuleFrommoduleList(列出模块){
可选op=modules.stream().filter(module->module.getArtifacts().stream().anyMatch(artifact->artifact.getType().equals(“ear”)).map(module->module.getKey()).findFirst();
如果(!op.isPresent()){
op=modules.stream().filter(module->module.getArtifacts().stream().anyMatch(artifact->artifact.getType().equals(“war”)).map(module->module.getKey()).reduce((a,b)->b);
}
返回op.orElse(空);
}

无论如何,也欢迎其他解决方案。如果有人添加了其他解决方案,我将尝试所有解决方案。

我建议您将此过程分解为几个函数。这并不意味着不鼓励Java8流链接操作,而是尽可能使它们清晰和原子化。我怀疑使用流比实际代码更好。流不适合在中间操作之间保持状态。另外,您当前的代码对所有工件进行一次遍历,而建议的解决方案进行两次遍历。如果您只想通过一次就可以完成此操作,我建议您创建自己的收集器(这里有很多关于创建收集器的问题,只需选择一个并从那里继续)如果使用您的代码段,我会遇到以下编译错误
类型列表的方法筛选器((m)->{})未定义,
类型ModuleUtil的方法getKey()未定义。
getKey()
方法是
模块
对象的一部分。@RITZXAVI我用记事本++而不是普通的IDE原型化了我的代码,出现了新的问题。我编辑了我的答案来修复它们,告诉我你是否仍然遇到问题。现在我得到了这个错误
可选类型中的方法orElse(模块)不适用于参数(可选)
@RITZXAVI-Phew!最后在我的IDE中编辑了它,应该可以了。错误是我正在输入
orElse
,它需要一个
模块
,返回值为
findFirst
,这是一个
可选的
。我只是用另一个
orElse
打开了最后一个
Optional
。再说一次,如果你仍然有问题,请告诉我。虽然它在语法上是正确的,但在功能上,它并没有达到我的预期。不管怎样,我已经想出了解决办法,我将发布。你可以查一下。谢谢您的尝试。如果我想要类型为'ear'或'war'的'deployableModuleKey',我认为您的代码很好。但是,我想要的是第一个类型为'ear'的'deployableModuleKey'。如果
ear
不存在,那么我想返回最后一个moduleKey,类型为'war'。此外,此代码返回工件键而不是模块键yes,在
工件
对象中没有名为
key
的属性。
public static ModuleKey getDeployableModuleFromModulesList(List<Module> modules) {
    Optional<ModuleKey> op = modules.stream().filter(module -> module.getArtifacts().stream().anyMatch(artifact -> artifact.getType().equals("ear"))).map(module -> module.getKey()).findFirst();
    if (!op.isPresent()) {
        op = modules.stream().filter(module -> module.getArtifacts().stream().anyMatch(artifact -> artifact.getType().equals("war"))).map(module -> module.getKey()).reduce((a, b) -> b);
    }
    return op.orElse(null);
}