《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)
扩展性 ⭐⭐⭐ 任意修改逻辑 ⭐☆☆ 只能分两路 ⭐⭐⭐ 可随时加分组 ⭐☆☆ 加组需改遍历
相关推荐
2301_8090511421 小时前
Linux 网络编程 学习笔记
linux·网络·学习
wanhengidc21 小时前
服务器租用有何优点
运维·服务器·安全·web安全
方也_arkling1 天前
【Java-Day08】static / final / 枚举
java·开发语言
坤昱1 天前
cfs调度类深入解刨——最新内核细节分析2
linux·服务器·cfs·cfs调度·eevdf调度·eevdf·kernel 7.1
橙淮1 天前
Spring Bean作用域与生命周期全解析
java·spring
艾莉丝努力练剑1 天前
【Linux:文件】Ext系列文件系统进阶
linux·运维·服务器·c++·文件系统·文件io·ext
海市公约1 天前
Linux核心基础命令与权限管理实战指南
linux·运维·服务器·vim·权限管理·系统监控·命令行
Chengbei111 天前
一站式源码安全检测工具、云安全 / APP / 小程序源码敏感信息递归多层目录扫描AK、JWT、手机号、身份证等敏感信息
java·开发语言·安全·web安全·网络安全·系统安全·安全架构
eggcode1 天前
【Qt学习】Linux(ARM架构)在线安装Qt6.x
linux·qt·学习·arm
wkd_0071 天前
Ubuntu 22.04 Samba 连接故障排查记:从“用户名或密码错误”到 NTLM 版本不兼容
linux·运维·ubuntu