《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)
扩展性 ⭐⭐⭐ 任意修改逻辑 ⭐☆☆ 只能分两路 ⭐⭐⭐ 可随时加分组 ⭐☆☆ 加组需改遍历
相关推荐
A小辣椒15 小时前
TShark:Wireshark CLI 功能
linux
唐青枫18 小时前
Java JDBC 实战指南:从 Connection 到事务和连接池
java
一个做软件开发的牛马19 小时前
MyBatis-Plus 从零实战:完整搭建可运行 Demo,BaseMapper 零 SQL、Wrapper 条件构造、分页插件与代码生成器详解
java·后端
用户37215742613519 小时前
Java 处理 PDF 图片:提取 PDF 中的图片,并压缩 PDF 图片体积
java
A小辣椒19 小时前
TShark:基础知识
linux
用户37215742613519 小时前
Java 打印 Word 文档:从基础打印到高级设置
java
AlfredZhao21 小时前
OCI 明明分配了 200G 系统盘,为什么 df 只看到 30G?
linux·oci
用户3521802454751 天前
当 Prompt 学会"热更新":Spring Boot × Nacos3 AI 实战
java·spring boot·ai编程
AlfredZhao1 天前
vi 删除指定范围的行,不用再反复按 dd
linux·vi
东坡白菜2 天前
破局全栈:一个前端开发的Java入门实战记录(1)
java·全栈