Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/341.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 是否可以使用一行将流收集到两个不同的集合?_Java_Java Stream - Fatal编程技术网

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

Java 是否可以使用一行将流收集到两个不同的集合?,java,java-stream,Java,Java Stream,我有以下代码:(简化为bravity) 公共void搜索(谓词、元素) { List searchResults=elements.stream() .filter(element->predicate.test(element.ownText())) .map(元素->新搜索结果(element.ownText()、element.baseUri()、element.tagName()) .collect(Collectors.toList()); } 但是现在,我想有另一个列表,它将包含没

我有以下代码:(简化为bravity)

公共void搜索(谓词、元素)
{
List searchResults=elements.stream()
.filter(element->predicate.test(element.ownText()))
.map(元素->新搜索结果(element.ownText()、element.baseUri()、element.tagName())
.collect(Collectors.toList());
}
但是现在,我想有另一个列表,它将包含没有映射的所有过滤元素。
是否可以使用流执行此操作,或者我是否应该为此更改为foreach循环?

您不能使用流两次,因为在使用collect时它是关闭的以下代码将抛出“java.lang.IllegalStateException:流已被操作或关闭”。因此,您需要创建两次流,或者为每个循环使用一个

import java.util.Collections;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

class Test
{
    static class SearchResult
    {
        SearchResult(Object o,Object p,Object q) {}
    }

    static class Element
    {
        public String ownText() {return "text";}
        public String tagName() {return "tag";}
        public String baseUri() {return "base";}
    }

    public static void search(Predicate<String> predicate, List<Element> elements)
    {
        Stream<Element> stream = elements.stream().filter(element -> predicate.test(element.ownText()));
        List<Element> filtered = stream.collect(Collectors.toList());
        // next line will throw the IllegalStateException as above line has already consumed the stream
        List<SearchResult> results =    stream.map(element -> 
         new SearchResult(element.ownText(),element.baseUri(),element.tagName()))
                .collect(Collectors.toList());
    }

    public static void main(String[] args)
    {       
        search(s->true,Collections.singletonList(new Element()));
    }
}
import java.util.Collections;
导入java.util.List;
导入java.util.function.Predicate;
导入java.util.stream.collector;
导入java.util.stream.stream;
课堂测试
{
静态类搜索结果
{
搜索结果(对象o、对象p、对象q){}
}
静态类元素
{
公共字符串ownText(){返回“text”;}
公共字符串标记名(){return“tag”;}
公共字符串baseUri(){返回“base”;}
}
公共静态void搜索(谓词谓词、列表元素)
{
Stream=elements.Stream().filter(element->predicate.test(element.ownText());
List filtered=stream.collect(Collectors.toList());
//下一行将抛出IllegalStateException,因为上一行已经消耗了流
列表结果=stream.map(元素->
新的搜索结果(element.ownText()、element.baseUri()、element.tagName())
.collect(Collectors.toList());
}
公共静态void main(字符串[]args)
{       
search(s->true,Collections.singletonList(新元素());
}
}

另一种选择是定义供应商:

这些解决方案是通用的:它们允许对单个数据源执行两种不同的操作。但在您的具体示例中,更容易创建过滤的非映射数据的第一个列表,然后在该列表上创建第二个流:

List<Element> elementList = elements.stream()
           .filter(element -> predicate.test(element.ownText()))
           .collect(Collectors.toList());
List<SearchResult> searchResults = elementList.stream()
           .map(element -> new SearchResult(element.ownText(),element.baseUri(),element.tagName()))
           .collect(Collectors.toList());
List elementList=elements.stream()
.filter(element->predicate.test(element.ownText()))
.collect(Collectors.toList());
List searchResults=elementList.stream()
.map(元素->新搜索结果(element.ownText()、element.baseUri()、element.tagName())
.collect(Collectors.toList());

一个简单的方法是

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());
List filteredElements=new ArrayList();
List searchResults=elements.stream()
.filter(element->predicate.test(element.ownText()))
.peek(过滤器删除::添加)
.map(元素->
新的搜索结果(element.ownText()、element.baseUri()、element.tagName())
.collect(Collectors.toList());

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

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());
}
公共void搜索(谓词、元素){
列表筛选器删除=
元素流()
.filter(element->predicate.test(element.ownText()))
.collect(Collectors.toList());
列表搜索结果=
filteredElements.stream()
.map(元素->新搜索结果(element.ownText()、element.baseUri()、element.tagName())
.collect(Collectors.toList());
}

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

您可以使用自定义收集器来完成。但另一个解决方案是使用两条流管道。美观大方!谢谢。使用peek给我一种非常不好的感觉,尽管我不能具体说明它有什么问题。这感觉像是对peek的滥用。@DavidConrad,因为“此方法主要用于支持调试,您希望在元素流过管道中的某个点时看到这些元素”。@DavidConrad您的感官可能会感到刺痛,因为
peek(filteredElements::add)
引入了副作用(将元素添加到
filteredElements
)。另外,当
elements.stream()时
返回一个并行流,
FilterElements
可能不包含所有过滤元素,因为ArrayList不是线程安全的。@DavidConrad我添加了一个答案,其中包含一个既线程安全又没有副作用的解决方案。我认为最后一种方法在这种情况下是最好的。但是实际上这里有3个非常不同的答案,可能是:他们是谁?
List<Element> elementList = elements.stream()
           .filter(element -> predicate.test(element.ownText()))
           .collect(Collectors.toList());
List<SearchResult> searchResults = elementList.stream()
           .map(element -> new SearchResult(element.ownText(),element.baseUri(),element.tagName()))
           .collect(Collectors.toList());
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());
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());
}