另一种方法是定义Supplier<Stream>:
public void search(Predicate<String> predicate, Elements elements)
{
Supplier<Stream<Element>> supplier = () -> elements.stream()
.filter(element -> predicate.test(element.ownText()));
List<SearchResult> searchResults = supplier.get()
.map(element -> new SearchResult(element.ownText(),element.baseUri(),element.tagName()))
.collect(Collectors.toList());
List<Element> elementList = supplier.get().collect(Collectors.toList());
}
请注意,使用这种方法实际上执行了两次过滤。
另一种(虽然在这种情况下不是很漂亮)解决方案是使用来自this answer 的pairing 收集器:
Collector<Element, ?, List<SearchResult>> c1 =
Collectors.mapping(element -> new SearchResult(element.ownText(),element.baseUri(),element.tagName()),
Collectors.toList());
Collector<Element, ?, List<Element>> c2 = Collectors.toList();
Collector<Element, ?, Pair<List<SearchResult>, List<Element>>> pairCollector =
pairing(c1, c2, Pair::new); // Assumes some Pair class existing
Pair<List<SearchResult>, List<Element>> result = elements.stream()
.filter(element -> predicate.test(element.ownText()))
.collect(pairing);
这些解决方案是通用的:它们允许对单个数据源执行两种不同的操作。但是在您的具体示例中,创建第一个过滤的非映射数据列表,然后在该列表上创建第二个流更容易:
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());