是否可以使用一行将流收集到两个不同的集合?

Mr.*_*pMe 4 java java-stream

我有以下代码:(为了勇敢而简化)

public void search(Predicate<String> predicate, Elements elements)
{
    List<SearchResult> searchResults = elements.stream()
        .filter(element -> predicate.test(element.ownText()))
        .map(element -> new SearchResult(element.ownText(), element.baseUri(),element.tagName()))
        .collect(Collectors.toList());
}
Run Code Online (Sandbox Code Playgroud)

但是现在,我想要另一个列表,该列表将包含没有映射的所有过滤元素。是否可以使用流来做到这一点,或者我应该为此更改为 foreach 循环?

Aca*_*nda 7

您可以收集过滤后的元素,然后使用此列表将元素映射到搜索结果:

public void search(Predicate<String> predicate, Elements elements) {
    List<Element> filteredElements = 
        elements.stream()
                .filter(element -> predicate.test(element.ownText()))
                .collect(Collectors.toList());

    List<SearchResult> searchResults = 
        filteredElements.stream()
                        .map(element -> new SearchResult(element.ownText(),element.baseUri(),element.tagName()))
                        .collect(Collectors.toList());
}
Run Code Online (Sandbox Code Playgroud)

这不会比其他答案的解决方案花费更多时间,但没有副作用,线程安全且易于阅读和理解。


Lou*_*man 6

一个简单的方法是

List<Element> filteredElements = new ArrayList<>();
List<SearchResult> searchResults = elements.stream()
      .filter(element -> predicate.test(element.ownText()))
      .peek(filteredElements::add)
      .map(element -> 
         new SearchResult(element.ownText(),element.baseUri(),element.tagName()))
      .collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)

  • 这种 peek 的使用给我一种非常糟糕的感觉,尽管我不能说明它有什么具体问题。感觉像是滥用窥视。 (4认同)
  • @DavidConrad 因为来自 [`peek` Javadoc](https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#peek-java.util.function.Consumer- ):“_这个方法的存在主要是为了支持调试,你想在其中看到元素流过管道中的某个点时_”。 (3认同)