如何使用Java 8流迭代嵌套for循环引用父元素?

时间:2015-03-24 14:43:29

标签: java java-8 java-stream optional

我想使用java8 streams迭代嵌套列表,并在第一次匹配时提取列表的一些结果。 不幸的是,如果子元素与过滤器匹配,我还必须从父内容中获取值。

我怎么能这样做?

java7

Result result = new Result();

//find first match and pupulate the result object.
for (FirstNode first : response.getFirstNodes()) {
    for (SndNode snd : first.getSndNodes()) {
        if (snd.isValid()) {
            result.setKey(first.getKey());
            result.setContent(snd.getContent());
            return;
        }
    }
}

java8

 response.getFirstNodes().stream()
        .flatMap(first -> first.getSndNodes())
        .filter(snd -> snd.isValid())
        .findFirst()
        .ifPresent(???); //cannot access snd.getContent() here

2 个答案:

答案 0 :(得分:12)

当您需要两个值并希望使用flatMap时(根据需要执行findFirst等短路操作时),您必须映射到包含两个值的对象

response.getFirstNodes().stream()
  .flatMap(first->first.getSndNodes().stream()
    .map(snd->new AbstractMap.SimpleImmutableEntry<>(first, snd)))
  .filter(e->e.getValue().isValid())
  .findFirst().ifPresent(e-> {
    result.setKey(e.getKey().getKey());
    result.setContent(e.getValue().getContent());
  });

为了仅使用标准类,我使用Map.Entry作为Pair类型,而真正的Pair类型可能看起来更简洁。

在此特定用例中,您可以将过滤器操作移动到内部流

response.getFirstNodes().stream()
  .flatMap(first->first.getSndNodes().stream()
     .filter(snd->snd.isValid())
     .map(snd->new AbstractMap.SimpleImmutableEntry<>(first, snd)))
  .findFirst().ifPresent(e-> {
    result.setKey(e.getKey().getKey());
    result.setContent(e.getValue().getContent());
  });

具有整洁的效果,只有一个匹配的项目,Map.Entry实例将被创建(好吧,应该the current implementation is not as lazy as it should,但即便如此,它仍然会创建比第一个变体更小的物体。)

答案 1 :(得分:-1)

应该是这样的:

编辑:感谢Holger指出代码不会停在第一个有效的FirstNode

response.getFirstNodes().stream()
  .filter(it -> {it.getSndNodes().stream().filter(SndNode::isValid).findFirst(); return true;})
  .findFirst()
  .ifPresent(first -> first.getSndNodes().stream().filter(SndNode::isValid).findFirst().ifPresent(snd -> {
    result.setKey(first.getKey());
    result.setContent(snd.getContent());
  }));

可以找到here

的测试