如何用Java Stream对Stream<Node>执行不同聚合操作?
问题描述
现有如下Node类:
public class Node { private String name; private List<Integer> list; // constructor, getters, etc. }
需要将Stream<Node>合并为单个Node对象,对两个字段执行不同聚合操作:
- 所有
name字段拼接成一个字符串 - 所有
list字段扁平化合并为一个列表
示例:
输入:
nodes = [ { Node(name="a", list=[1,2]) }, { Node(name="b", list=[3,4]) } ]
输出:
result = { Node(name="ab", list=[1,2,3,4]) }
已知可以用flatMap()扁平化列表、Collectors.joining()拼接字符串,但不清楚如何在同一个Stream中同时执行这两种转换,请问如何通过Stream实现该功能?
List<Node> nodes = getMyNodes(); nodes.stream().????
解决方案
方法一:使用Collectors.teeing(Java 12+)
Java 12引入的Collectors.teeing专门用于同时执行两种收集操作并合并结果,完美适配需求:
Node result = nodes.stream() .collect(Collectors.teeing( // 收集所有name并拼接 Collectors.mapping(Node::getName, Collectors.joining()), // 扁平化所有list并收集为一个列表 Collectors.flatMapping(node -> node.getList().stream(), Collectors.toList()), // 将两个收集结果合并为新Node (joinedName, mergedList) -> new Node(joinedName, mergedList) ));
说明
- 第一个收集器:通过
mapping提取每个Node的name,再用joining()完成字符串拼接 - 第二个收集器:通过
flatMapping将每个Node的list转为Stream并扁平化,最终收集为一个完整的List - 合并函数:把两个收集结果传入Node构造器,生成最终的合并对象
方法二:兼容Java 8+的实现方案
如果你的Java版本低于12,可以用以下两种方式实现:
方式1:使用reduce直接合并
Node result = nodes.stream() .reduce(new Node("", new ArrayList<>()), (accumulator, currentNode) -> { // 拼接name String combinedName = accumulator.getName() + currentNode.getName(); // 合并list List<Integer> combinedList = new ArrayList<>(accumulator.getList()); combinedList.addAll(currentNode.getList()); return new Node(combinedName, combinedList); });
注意:这种方式每次迭代都会创建新的Node和List对象,数据量较大时性能一般。
方式2:自定义Collector(性能优化版)
使用可变容器作为累加器,避免频繁创建对象,同时保持原始Node类的不可变性:
// 定义一个可变辅助类用于累加 class MutableNode { private final StringBuilder nameBuilder = new StringBuilder(); private final List<Integer> mergedList = new ArrayList<>(); public void merge(Node node) { nameBuilder.append(node.getName()); mergedList.addAll(node.getList()); } // 转换为不可变的Node对象 public Node toNode() { return new Node(nameBuilder.toString(), new ArrayList<>(mergedList)); } } // 收集流程 Node result = nodes.stream() .collect(Collector.of( MutableNode::new, // 初始化累加器 MutableNode::merge, // 处理每个元素 (left, right) -> { // 并行流时合并两个累加器 left.nameBuilder.append(right.nameBuilder); left.mergedList.addAll(right.mergedList); return left; }, MutableNode::toNode // 转换为最终的Node对象 ));
内容的提问来源于stack exchange,提问作者Dejan
相关产品推荐
相关产品推荐

