You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 09:40:47