Java案例怎么按字段分组数据?

wen java案例 12

本文目录导读:

Java案例怎么按字段分组数据?

  1. 基础示例:按单个字段分组
  2. 按多个字段分组
  3. 分组后统计数据
  4. 分组后转换数据
  5. 使用传统方式(Java 8之前)
  6. 处理复杂的分组场景
  7. 注意事项

在Java中按字段分组数据,最常用的方法是使用 Stream APICollectors.groupingBy() 方法(Java 8+),以下是几种常见场景的示例:

基础示例:按单个字段分组

import java.util.*;
import java.util.stream.Collectors;
public class GroupByExample {
    public static void main(String[] args) {
        // 创建数据
        List<Student> students = Arrays.asList(
            new Student("张三", "A班", 85),
            new Student("李四", "B班", 92),
            new Student("王五", "A班", 78),
            new Student("赵六", "B班", 95),
            new Student("钱七", "A班", 88)
        );
        // 按班级分组
        Map<String, List<Student>> groupByClass = students.stream()
            .collect(Collectors.groupingBy(Student::getClassName));
        // 打印结果
        groupByClass.forEach((className, studentList) -> {
            System.out.println("班级: " + className);
            studentList.forEach(s -> System.out.println("  " + s.getName()));
        });
    }
}
class Student {
    private String name;
    private String className;
    private int score;
    // 构造方法、getter/setter省略
    public Student(String name, String className, int score) {
        this.name = name;
        this.className = className;
        this.score = score;
    }
    public String getName() { return name; }
    public String getClassName() { return className; }
    public int getScore() { return score; }
}

按多个字段分组

// 创建复合键类
class ClassGradeKey {
    private String className;
    private String grade;
    public ClassGradeKey(String className, String grade) {
        this.className = className;
        this.grade = grade;
    }
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        ClassGradeKey that = (ClassGradeKey) o;
        return Objects.equals(className, that.className) && 
               Objects.equals(grade, that.grade);
    }
    @Override
    public int hashCode() {
        return Objects.hash(className, grade);
    }
}
// 使用示例
Map<ClassGradeKey, List<Student>> multiGroup = students.stream()
    .collect(Collectors.groupingBy(
        s -> new ClassGradeKey(s.getClassName(), s.getGrade())
    ));

分组后统计数据

// 按班级分组,统计每个班的人数
Map<String, Long> countByClass = students.stream()
    .collect(Collectors.groupingBy(
        Student::getClassName, 
        Collectors.counting()
    ));
// 按班级分组,计算平均分
Map<String, Double> avgScoreByClass = students.stream()
    .collect(Collectors.groupingBy(
        Student::getClassName,
        Collectors.averagingInt(Student::getScore)
    ));
// 按班级分组,找出最高分
Map<String, Optional<Student>> maxScoreByClass = students.stream()
    .collect(Collectors.groupingBy(
        Student::getClassName,
        Collectors.maxBy(Comparator.comparingInt(Student::getScore))
    ));

分组后转换数据

// 按班级分组,只提取姓名列表
Map<String, List<String>> namesByClass = students.stream()
    .collect(Collectors.groupingBy(
        Student::getClassName,
        Collectors.mapping(Student::getName, Collectors.toList())
    ));
// 按班级分组,将学生对象转换为分数列表
Map<String, List<Integer>> scoresByClass = students.stream()
    .collect(Collectors.groupingBy(
        Student::getClassName,
        Collectors.mapping(Student::getScore, Collectors.toList())
    ));

使用传统方式(Java 8之前)

// 传统方式分组
Map<String, List<Student>> groupByClass = new HashMap<>();
for (Student student : students) {
    String className = student.getClassName();
    groupByClass.computeIfAbsent(className, k -> new ArrayList<>()).add(student);
}

处理复杂的分组场景

// 根据分数范围分组
Map<String, List<Student>> groupByScoreRange = students.stream()
    .collect(Collectors.groupingBy(s -> {
        int score = s.getScore();
        if (score >= 90) return "优秀";
        else if (score >= 80) return "良好";
        else if (score >= 60) return "及格";
        else return "不及格";
    }));
// 按多个字段分组(使用字符串拼接作为key)
Map<String, List<Student>> groupByMultipleFields = students.stream()
    .collect(Collectors.groupingBy(
        s -> s.getClassName() + "-" + s.getGrade()
    ));

注意事项

  1. 排序问题groupingBy() 不保证分组结果的顺序,如果需要有序可以使用 groupingBy() 的重载版本:

    // 按班级分组,保持插入顺序
    Map<String, List<Student>> groupByClass = students.stream()
        .collect(Collectors.groupingBy(
            Student::getClassName,
            LinkedHashMap::new,  // 使用LinkedHashMap保持顺序
            Collectors.toList()
        ));
  2. null值处理:分组字段为null时,会创建key为null的分组,建议使用 Objects::nonNull 过滤。

这些方法适用于大多数按字段分组的需求,选择哪种方式取决于你的具体业务场景。

抱歉,评论功能暂时关闭!