我需要对元素列表进行简单的遍历,对所有元素执行某种转换,然后将所有结果累积到列表中。 像这样:
List<GraphEdge> edges = new LinkedList<GraphEdge>();
for (CrawlResult result : crawlResults) {
edges.addAll(resultToEdges(result));
}
这段代码需要4行,没有什么能比让我在一行中更快乐。因此,java 8流(map + reduce)用于救援。
我尝试使用以下行:
List<GraphEdge> edges = graphResults.stream().
map(res -> resultToEdges(res)).
reduce(new LinkedList<GraphEdge>(), (list, res) -> list.addAll(res));
它没有通过编译,因为reduce的第二个参数应返回一个List,但它返回一个布尔值,这是addAll方法的返回类型。
当然,这种方式可行:
List<GraphEdge> edges = graphResults.stream().
map(res -> resultToEdges(res)).
reduce(new LinkedList<GraphEdge>(), (list, res) ->
{ list.addAll(res); return list; });
但它并不那么优雅。 还有其他任何方式吗?
答案 0 :(得分:6)
无论如何,使用reduce来处理这类事情是错误的(参见this thread)。但是,您可以使用flatMap
代替map
,并将最终Stream
收集到List
中:
List<GraphEdge> edges = graphResults.stream()
.flatMap(res -> resultToEdges(res).stream())
.collect(toList()); //or toCollection with a concrete implementation, you can check the docs
flatMap
只是一张地图,后面是展平操作(并不奇怪),例如:
[[1, 2], [3, 4]].flatMap(x -> x.add(5)) //imagine that add returns a list
将首先应用映射:
[[1, 2, 5], [3, 4, 5]]
然后展平列表,以便获得:
[1, 2, 5, 3, 4, 5]
答案 1 :(得分:5)
无需使用reduce
。
List<GraphEdge> edges = graphResults.stream().
flatMap(res -> resultToEdges(res).stream()).
collect(Collectors.toList());
这假设resultToEdges(res)
返回GraphEdge
的List(或其他一些Collection),这似乎是这种情况。
答案 2 :(得分:3)
不要使用reduce
进行可变缩减。它不仅不优雅。这是错误的,如果流是并行的,它将无法正常工作。使用flatMap
作为其他答案建议,或者collect
的3参数版本与reduce
类似,但设计用于可变累加器:
List<GraphEdge> edges = graphResults.stream()
.map(res -> resultToEdges(res))
.collect(LinkedList::new, LinkedList::addAll, LinkedList::addAll);
答案 3 :(得分:2)
正如已经指出的那样,没有必要减少。如果您想要LinkedList
作为返回值,可以使用:
List<GraphEdge> edges = graphResults.stream()
.flatMap(res -> resultToEdges(res).stream())
.collect(toCollection(LinkedList::new));
答案 4 :(得分:0)
在函数式语言中,通常有不可变的列表和函数,它们会追加/连接并返回一个新的不可变List。那会给你一个lambda的单线解决方案。 Alas Java没有这样的方法..