当前位置: 首页 > article >正文

java8 list分组

在 Java 8 中,可以使用 Stream APICollectors.groupingByList 进行分组。以下是常见的分组场景和实现方法:


1. 基础分组(按对象属性分组)

根据对象的某个字段分组(例如按 category 分组):

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

class Product {
    private String category;
    private String name;

    // 构造方法、Getter/Setter 省略
}

List<Product> products = ...;

// 按 category 分组
Map<String, List<Product>> groupedByCategory = products.stream()
    .collect(Collectors.groupingBy(Product::getCategory));

2. 分组后统计(如计数、求和)

分组后对每组数据进行统计:

// 按 category 分组,统计每组的数量
Map<String, Long> countByCategory = products.stream()
    .collect(Collectors.groupingBy(
        Product::getCategory,
        Collectors.counting()
    ));

// 按 category 分组,计算每组的总价(假设有 getPrice() 方法)
Map<String, Double> sumByCategory = products.stream()
    .collect(Collectors.groupingBy(
        Product::getCategory,
        Collectors.summingDouble(Product::getPrice)
    ));

3. 复杂条件分组

使用 Lambda 表达式自定义分组逻辑:

// 按价格范围分组(如 <100, 100-500, >500)
Map<String, List<Product>> groupByPriceRange = products.stream()
    .collect(Collectors.groupingBy(p -> {
        if (p.getPrice() < 100) return "Low";
        else if (p.getPrice() <= 500) return "Medium";
        else return "High";
    }));

4. 多级分组(嵌套分组)

先按 category 分组,再按 subCategory 分组:

Map<String, Map<String, List<Product>>> multiGrouping = products.stream()
    .collect(Collectors.groupingBy(
        Product::getCategory,
        Collectors.groupingBy(Product::getSubCategory)
    ));

5. 分组后对值进行处理

分组后对值进行转换(如提取名称):

// 按 category 分组,提取每组的名称集合
Map<String, List<String>> namesByCategory = products.stream()
    .collect(Collectors.groupingBy(
        Product::getCategory,
        Collectors.mapping(Product::getName, Collectors.toList())
    ));

6. 过滤后再分组

先过滤数据再分组:

// 过滤价格 > 0 的商品后按 category 分组
Map<String, List<Product>> filteredGroup = products.stream()
    .filter(p -> p.getPrice() > 0)
    .collect(Collectors.groupingBy(Product::getCategory));

完整示例

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class GroupingDemo {
    public static void main(String[] args) {
        List<Product> products = Arrays.asList(
            new Product("Electronics", "Laptop", 1200.0),
            new Product("Electronics", "Phone", 800.0),
            new Product("Books", "Java Guide", 50.0)
        );

        // 按 category 分组
        Map<String, List<Product>> byCategory = products.stream()
            .collect(Collectors.groupingBy(Product::getCategory));

        // 输出结果
        byCategory.forEach((category, list) -> {
            System.out.println("Category: " + category);
            list.forEach(p -> System.out.println("  " + p.getName()));
        });
    }
}

class Product {
    private String category;
    private String name;
    private double price;

    public Product(String category, String name, double price) {
        this.category = category;
        this.name = name;
        this.price = price;
    }

    // Getters 省略
}

关键点

  • Collectors.groupingBy:核心分组方法。
  • 方法引用:如 Product::getCategory 简化代码。
  • 下游收集器:如 Collectors.counting()Collectors.toList() 处理分组后的数据。

根据具体需求选择合适的分组方式!

**

分组key 自定义

**

在 Java 8 中实现多级分组时,若需要将中文的 Key 转换为预定义的码值(如枚举、编码或英文缩写),可以通过以下步骤完成:


步骤 1:定义中文到码值的映射关系

使用 Map 或枚举类维护中文与码值的对应关系。例如:

// 方式 1:静态 Map 存储映射
private static final Map<String, String> CATEGORY_CODE_MAP = new HashMap<>();
static {
    CATEGORY_CODE_MAP.put("电子产品", "ELEC");
    CATEGORY_CODE_MAP.put("书籍", "BOOK");
    // 更多映射...
}

// 方式 2:使用枚举
public enum CategoryCode {
    ELECTRONICS("电子产品", "ELEC"),
    BOOKS("书籍", "BOOK");

    private final String chineseName;
    private final String code;

    CategoryCode(String chineseName, String code) {
        this.chineseName = chineseName;
        this.code = code;
    }

    public static String getCode(String chineseName) {
        return Arrays.stream(values())
            .filter(e -> e.chineseName.equals(chineseName))
            .findFirst()
            .map(e -> e.code)
            .orElse("UNKNOWN");  // 默认值
    }
}

步骤 2:在分组时转换 Key

使用 groupingBy 时,通过映射关系将中文转为码值:

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

class Product {
    private String category;  // 中文分类,如 "电子产品"
    private String subCategory; // 中文子分类,如 "手机"
    // 其他字段和方法...
}

List<Product> products = ...;

// 多级分组(按 category -> subCategory)
Map<String, Map<String, List<Product>>> groupedProducts = products.stream()
    .collect(Collectors.groupingBy(
        // 第一级分组:中文 category 转码值
        product -> CATEGORY_CODE_MAP.getOrDefault(
            product.getCategory(), 
            "DEFAULT_CODE"  // 处理未匹配的情况
        ),
        // 第二级分组:中文 subCategory 转码值
        Collectors.groupingBy(
            product -> CategoryCode.getCode(product.getSubCategory())  // 使用枚举转换
        )
    ));

步骤 3:处理未匹配的中文 Key

如果存在未定义的中文 Key,需设置默认值或抛出异常:

// 使用 getOrDefault 设置默认值
product -> CATEGORY_CODE_MAP.getOrDefault(product.getCategory(), "UNKNOWN")

// 或抛出明确异常
product -> {
    String code = CATEGORY_CODE_MAP.get(product.getCategory());
    if (code == null) {
        throw new IllegalArgumentException("未找到分类编码: " + product.getCategory());
    }
    return code;
}

完整示例

import java.util.*;
import java.util.stream.Collectors;

public class MultiLevelGroupingWithCode {
    // 定义中文到码值的映射
    private static final Map<String, String> CATEGORY_CODE_MAP = new HashMap<>();
    static {
        CATEGORY_CODE_MAP.put("电子产品", "ELEC");
        CATEGORY_CODE_MAP.put("书籍", "BOOK");
    }

    private static final Map<String, String> SUB_CATEGORY_CODE_MAP = new HashMap<>();
    static {
        SUB_CATEGORY_CODE_MAP.put("手机", "PHONE");
        SUB_CATEGORY_CODE_MAP.put("笔记本电脑", "LAPTOP");
        SUB_CATEGORY_CODE_MAP.put("编程书籍", "PROG_BOOK");
    }

    public static void main(String[] args) {
        List<Product> products = Arrays.asList(
            new Product("电子产品", "手机"),
            new Product("电子产品", "笔记本电脑"),
            new Product("书籍", "编程书籍")
        );

        // 多级分组:中文转码值
        Map<String, Map<String, List<Product>>> grouped = products.stream()
            .collect(Collectors.groupingBy(
                p -> CATEGORY_CODE_MAP.getOrDefault(p.getCategory(), "UNKNOWN"),
                Collectors.groupingBy(
                    p -> SUB_CATEGORY_CODE_MAP.getOrDefault(p.getSubCategory(), "UNKNOWN")
                )
            ));

        // 输出结果
        grouped.forEach((categoryCode, subMap) -> {
            System.out.println("Category Code: " + categoryCode);
            subMap.forEach((subCode, list) -> {
                System.out.println("  Sub-Category Code: " + subCode);
                list.forEach(p -> System.out.println("    " + p));
            });
        });
    }
}

class Product {
    private String category;
    private String subCategory;

    public Product(String category, String subCategory) {
        this.category = category;
        this.subCategory = subCategory;
    }

    // Getters...
}

输出结果

Category Code: ELEC
  Sub-Category Code: PHONE
    Product{category='电子产品', subCategory='手机'}
  Sub-Category Code: LAPTOP
    Product{category='电子产品', subCategory='笔记本电脑'}
Category Code: BOOK
  Sub-Category Code: PROG_BOOK
    Product{category='书籍', subCategory='编程书籍'}

优化建议

  1. 集中管理映射关系
    将映射存储在配置文件或数据库中,提高灵活性。

  2. 使用工具类
    封装中文到码值的转换逻辑:

    public class CodeConverter {
        public static String getCategoryCode(String chineseName) {
            // 实现转换逻辑
        }
        public static String getSubCategoryCode(String chineseName) {
            // 实现转换逻辑
        }
    }
    
  3. 防御性编程
    确保所有可能的中文 Key 都有对应的码值,避免 NullPointerException

通过这种方式,可以在分组时动态将中文 Key 转换为业务需要的码值!


http://www.kler.cn/a/574375.html

相关文章:

  • JavaWeb-idea配置smart tomcat
  • 大数据环境(单机版) Flume传输数据到Kafka
  • 算法之 前缀和
  • vector详解
  • netty中Future和ChannelHandler
  • 鸿蒙Next网络请求~上传文件pdf
  • SCI1区TOP:自适应学习粒子群算法SLPSO,深度解析+性能实测
  • 23种设计模式之单例模式(Singleton Pattern)【设计模式】
  • 智能文档制度管理系统技术
  • istio从入门到精通(1)
  • vue+neo4j 四大名著知识图谱问答系统
  • es 慢查询引起 cpu报警处理方法
  • 计算机毕业设计Python+Django+Vue3微博数据舆情分析平台 微博用户画像系统 微博舆情可视化(源码+ 文档+PPT+讲解)
  • Java,Golang,Rust 泛型的大体对比小记
  • 验证测试 .NET 10 预览版的 Windows 窗体中的剪贴板新增功能
  • 【1Panel】平替宝塔面板!1Panel面板香橙派部署结合内网穿透远程管理
  • 第5章:vuex
  • C++ Primer 拷贝控制和资源管理
  • 嵌入式 ARM Linux 系统构成(2):Linux内核层
  • 文本处理Bert面试内容整理-如何使用BERT进行微调?