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

如何使用Java Streams简化同ID对象合并与列表类型转换

问题解答

你当前的实现存在两个明显问题:一是需要二次遍历全量列表,时间复杂度为O(n²),数据量较大时性能差;二是在Stream的map操作中修改外部ImprovedCustomer对象的属性,存在副作用,使用并行流时会出现线程安全问题。

可以直接使用JDK Stream提供的groupingBy分组收集器实现需求,仅需一次主遍历即可完成转换,逻辑更简洁也更符合函数式编程规范。

实现代码

如果需要保持和样例一致的输出顺序(按id首次出现的顺序排列),可以指定LinkedHashMap作为分组的Map容器,代码如下:

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.stream.Collectors;

public class App {

    public static void main(String[] args) {
        List<Customer> list = new ArrayList<>();
        list.add(new Customer(1, "jon", "fiat", "black"));
        list.add(new Customer(2, "din", "ford", "yellow"));
        list.add(new Customer(1, "jon", "benz", "white"));
        list.add(new Customer(1, "jon", "volvo", "red"));
        list.add(new Customer(3, "fin", "volvo", "black"));
        list.add(new Customer(3, "fin", "fiat", "green"));
        list.add(new Customer(4, "lara", "bmw", "red"));
        list.add(new Customer(5, "tina", "toyota", "white"));
        list.add(new Customer(5, "tina", "fiat", "yelow"));
        list.add(new Customer(6, "bogi", "benz", "black"));

        // 核心转换逻辑
        List<ImprovedCustomer> improvedCustomers = list.stream()
                .collect(Collectors.groupingBy(
                        Customer::getId,
                        LinkedHashMap::new, // 保证分组顺序和id首次出现顺序一致
                        Collectors.collectingAndThen(Collectors.toList(), sameIdCustomers -> {
                            Customer firstCus = sameIdCustomers.get(0);
                            List<Car> cars = sameIdCustomers.stream()
                                    .map(c -> new Car(c.getCarType(), c.getColor()))
                                    .collect(Collectors.toList());
                            return new ImprovedCustomer(firstCus.getId(), firstCus.getName(), cars);
                        })
                ))
                .values()
                .stream()
                .collect(Collectors.toList());
    }

    // 原有Customer、Car、ImprovedCustomer类定义无需修改
}

逻辑说明

  • 核心逻辑是按id对原始Customer列表做分组,同一id的所有客户数据会被聚合到同一个列表中
  • 分组过程中通过collectingAndThen直接对同组数据做转换:同一id对应的name固定,直接取同组第一个元素的id和name即可,再遍历同组元素转成Car列表,直接构造出完整的ImprovedCustomer对象
  • 最后取出分组Map中所有的value,就是最终需要的ImprovedCustomer列表
  • 如果不需要保持输出顺序,可以去掉groupingBy参数中的LinkedHashMap::new,默认使用HashMap存储分组结果性能略高,但无法保证输出顺序和原列表id出现顺序一致;保留该参数时输出结果和你给出的样例顺序完全匹配
  • 整个逻辑没有嵌套遍历全量列表的操作,时间复杂度为O(n),性能优于原有实现,同时不存在修改外部对象的副作用,并行执行也不会有线程安全问题。

内容的提问来源于stack exchange,提问作者Jix

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 06:45:31