《Java 数据分组的四种姿势:从 for 循环到 Stream API》

分离SideType=0.5和1的数据

for循环

java 复制代码
        // 3. 分离SideType=0.5和1的数据
        List<SlaughterWeigh> needMergeList = new ArrayList<>();
        List<SlaughterWeigh> normalList = new ArrayList<>();

        for (SlaughterWeigh record : originalList) {
            if ("0.5".equals(record.getSideType())) {
                needMergeList.add(record);
            } else {
                normalList.add(record);
            }
        }

Stream 流方案

方案 1:使用 Collectors.partitioningBy(推荐)

java 复制代码
Map<Boolean, List<SlaughterWeigh>> partitioned = originalList.stream()
    .collect(Collectors.partitioningBy(r -> "0.5".equals(r.getSideType())));

List<SlaughterWeigh> needMergeList = partitioned.get(true);   // 边口类型 0.5
List<SlaughterWeigh> normalList = partitioned.get(false);       // 其他

特点:

  • 专为二分类设计(true/false)
  • 底层优化,使用 Partition 对象,内存效率高
  • 不会返回 null,空分组返回空列表 []
  • 只能分两组,不能扩展

输出结构:

Map<Boolean, List<SlaughterWeigh>>

├── true → 记录1(0.5), 记录3(0.5), ... // needMergeList

└── false → 记录2(1), 记录4(null), ... // normalList

方案 2:使用 Collectors.groupingBy

java 复制代码
Map<String, List<SlaughterWeigh>> grouped = originalList.stream()
    .collect(Collectors.groupingBy(r -> {
        if ("0.5".equals(r.getSideType())) return "half";
        else if ("1".equals(r.getSideType())) return "whole";
        else return "unknown";
    }));

List<SlaughterWeigh> halfList = grouped.getOrDefault("half", new ArrayList<>());
List<SlaughterWeigh> wholeList = grouped.getOrDefault("whole", new ArrayList<>());
List<SlaughterWeigh> unknownList = grouped.getOrDefault("unknown", new ArrayList<>());

特点:

  • 可分多组(2 组、3 组、N 组)
  • 键可以是任意类型(String、Enum 等)
  • 可能返回 null(需用 getOrDefault
  • 适合复杂分类场景

你的场景:只分两组(0.5 和非 0.5),用 groupingBy 有点大材小用

方案 3:两次 filter(效率较低,不推荐)

java 复制代码
List<SlaughterWeigh> needMergeList = originalList.stream()
    .filter(r -> "0.5".equals(r.getSideType()))
    .collect(Collectors.toList());

List<SlaughterWeigh> normalList = originalList.stream()
    .filter(r -> !"0.5".equals(r.getSideType()))
    .collect(Collectors.toList());

特点:

  • 代码看着简洁
  • 性能最差:遍历两次列表
  • 列表很大时(如 10 万条),耗时是其他方式的 2 倍
  • 每增加一个分组就要多遍历一次

对比

方案 优点 缺点
当前 for 循环 直观易懂,一次遍历 代码稍长
partitioningBy 一次遍历,返回 Map 需要理解 API
groupingBy 灵活,可多分组 稍复杂
两次 filter 简洁 遍历两次,效率低
对比维度 for 循环 partitioningBy groupingBy 两次 filter
代码行数 6 行 4 行 4 行 4 行
遍历次数 1 次 ✅ 1 次 ✅ 1 次 ✅ 2 次 ❌
时间复杂度 O(n) O(n) O(n) O(2n)
创建列表数 2 个 2 个(在 Map 中) 2 个(在 Map 中) 2 个
空值安全性 完全控制 不会返回 null,空列表自动处理 可能返回 null(需 getOrDefault) 不会返回 null
适用分组数 任意 只能 2 组(true/false) 任意多组 每组需一次遍历
你的场景适配 ⭐⭐⭐ 完美适配 ⭐⭐⭐ 完美适配(二分类) ⭐⭐☆ 杀鸡用牛刀 ⭐☆☆ 性能差
可读性(新手) ⭐⭐⭐ 最直观 ⭐⭐☆ 需了解 API ⭐⭐☆ 需了解 API ⭐⭐⭐ 直观
可读性(熟练) ⭐⭐☆ 略啰嗦 ⭐⭐⭐ 函数式简洁 ⭐⭐⭐ 函数式简洁 ⭐☆☆ 重复遍历
调试难度 ⭐⭐⭐ 易调试(可打断点) ⭐⭐☆ 需熟悉 Stream ⭐⭐☆ 需熟悉 Stream ⭐⭐⭐ 易调试
空列表处理 已创建,可直接用 返回空列表(非 null) 可能返回 null 返回空列表(非 null)
扩展性 ⭐⭐⭐ 任意修改逻辑 ⭐☆☆ 只能分两路 ⭐⭐⭐ 可随时加分组 ⭐☆☆ 加组需改遍历
相关推荐
菜地里的小菜鸟4 小时前
将linux程序打成.run包
linux·将linux程序打成run包·运维自动安装包
麻瓜生活睁不开眼4 小时前
Android16修改全局桌面视图边框四直角显示为弧边圆角
android·java·深度学习
dear_bi_MyOnly4 小时前
【MyBatis 操作数据库】
java·数据库·学习·mybatis·学习方法
2601_953720825 小时前
【计算机毕业设计】基于Spring Boot的心理健康咨询与评测系统的设计与实现
java·spring boot·后端
丈剑走天涯6 小时前
JDK 17 正式特性
java·开发语言
圣光SG6 小时前
Java操作题练习(七)
java·开发语言·算法
土星云SaturnCloud6 小时前
边缘侧大模型部署的新利器——国科环宇GK 300I大模型一体机深度评测与架构解析
服务器·人工智能·ai·边缘计算
晚风吹长发7 小时前
Docker基础——Docker Network(网络详解)
linux·运维·网络·ubuntu·docker·容器
Cx330_FCQ7 小时前
Tmux使用
服务器·git·算法
@航空母舰8 小时前
SpringBoot通过Map实现天然的策略模式
java·spring boot·后端