Java使用groupingBy分组数据乱序问题解决方案

业务背景

假设当前有一个对学生进行各方面评价的对象,评价包括考察模块、考察点、评价备注。字段关系为,同一模块包含多个考察点,每个考察点有一个评价备注。
对象代码如下
/**
 * 评价信息对象
 */
@Data
@AllArgsConstructor
class Evaluation {

    /**
     * 考查模块
     */
    private String inspectionModule;

    /**
     * 考察点
     */
    private String inspectionPoint;

    /**
     * 评价备注
     */
    private String remark;
}

接下来我们做一些测试数据,看起来会直观一些
    public static void main(String[] args) {
        List<Evaluation> list = new ArrayList<>() {{
            add(new Evaluation("课上表现", "专注力", "上课的时候很专注"));
            add(new Evaluation("课上表现", "表达能力", "表达能力还可以"));
            add(new Evaluation("逻辑思维", "清晰度", "思路比较清晰"));
            add(new Evaluation("逻辑思维", "敏捷程度", "反应有点迟钝"));
            add(new Evaluation("课后作业", "卷面分", "卷面干净整节"));
            add(new Evaluation("课后作业", "正确率", "大约90%的样子"));
        }};
        list.forEach(System.out::println);
    }
这里我们把创建的测试对象集合打印出来(控制台打印信息如下)

Java使用groupingBy分组数据乱序问题解决方案_第1张图片

看图我们可以更加直观地看到我们数据是1个模块2个考察点这样的关系,这个时候,我们想要按照考察模块对数据进行分组。很简单,使用stream中的groupingBy即可。

技术实现

我们直接上代码
    public static void main(String[] args) {
        List<Evaluation> list = new ArrayList<>() {{
            add(new Evaluation("课上表现", "专注力", "上课的时候很专注"));
            add(new Evaluation("课上表现", "表达能力", "表达能力还可以"));
            add(new Evaluation("逻辑思维", "清晰度", "思路比较清晰"));
            add(new Evaluation("逻辑思维", "敏捷程度", "反应有点迟钝"));
            add(new Evaluation("课后作业", "卷面分", "卷面干净整节"));
            add(new Evaluation("课后作业", "正确率", "大约90%的样子"));
        }};
        list.forEach(System.out::println);
        Map<String, List<Evaluation>> map = list.stream().collect(Collectors.groupingBy(Evaluation::getInspectionModule));
        map.forEach((s, evaluations) -> System.out.println(s + ": " + evaluations));
    }
运行结果是怎样的呢?(控制台打印信息如下)

在这里插入图片描述

数据确实根据考察模块进行了聚合,但是它的顺序却不是按照我们事先安排好的顺序,那么原因是什么呢?我们在数据聚合成map之后,打印一下这个map的信息即可知道原因。
System.out.println(map.getClass().getSimpleName());
打印出来的信息是“HashMap”,原因找到了,因为聚合后的数据是用HashMap来收集的,所以打乱了原本的顺序。

Java使用groupingBy分组数据乱序问题解决方案_第2张图片

查看源码我们也能看出来,groupingBy默认使用HashMap来收集数据。因此我们只需要把HashMap换成LinkedHashMap即可解决这个问题。

Java使用groupingBy分组数据乱序问题解决方案_第3张图片

通过阅读源码我们也能看到,groupingBy本身也是支持我们去自定义一个Map实例去收集数据的。

代码优化

    public static void main(String[] args) {
        List<Evaluation> list = new ArrayList<>() {{
            add(new Evaluation("课上表现", "专注力", "上课的时候很专注"));
            add(new Evaluation("课上表现", "表达能力", "表达能力还可以"));
            add(new Evaluation("逻辑思维", "清晰度", "思路比较清晰"));
            add(new Evaluation("逻辑思维", "敏捷程度", "反应有点迟钝"));
            add(new Evaluation("课后作业", "卷面分", "卷面干净整节"));
            add(new Evaluation("课后作业", "正确率", "大约90%的样子"));
        }};
        list.forEach(System.out::println);
        Map<String, List<Evaluation>> map = list.stream().collect(Collectors.groupingBy(Evaluation::getInspectionModule, LinkedHashMap::new, Collectors.toList()));
        map.forEach((s, evaluations) -> System.out.println(s + ": " + evaluations));
    }
运行结果如下

在这里插入图片描述

Finish

题外话

优化聚合后的数据,增强数据可读性
    public static void main(String[] args) {
        //创建测试数据
        List<Evaluation> list = new ArrayList<>() {{
            add(new Evaluation("课上表现", "专注力", "上课的时候很专注"));
            add(new Evaluation("课上表现", "表达能力", "表达能力还可以"));
            add(new Evaluation("逻辑思维", "清晰度", "思路比较清晰"));
            add(new Evaluation("逻辑思维", "敏捷程度", "反应有点迟钝"));
            add(new Evaluation("课后作业", "卷面分", "卷面干净整节"));
            add(new Evaluation("课后作业", "正确率", "大约90%的样子"));
        }};
        //打印集合
        list.forEach(System.out::println);
        //根据考察模块进行数据聚合
        Map<String, List<Evaluation>> map = list.stream().collect(Collectors.groupingBy(Evaluation::getInspectionModule, LinkedHashMap::new, Collectors.toList()));
        //打印map实现类
        System.out.println(map.getClass().getSimpleName());
        //打印聚合后的数据
        map.forEach((s, evaluations) -> System.out.println(s + ": " + evaluations));
        //数据可读性优化
        StringBuilder msg = new StringBuilder();
        map.forEach((s, evaluations) -> {
            msg.append(s).append(":\r\n");
            evaluations.forEach(inspectDetail -> msg.append(inspectDetail.getInspectionPoint()).append(": ")
                    .append(inspectDetail.getRemark()).append("\r\n"));
        });
        System.out.println(msg);
    }
运行结果如下

Java使用groupingBy分组数据乱序问题解决方案_第4张图片

完整的代码片段在这里 码云代码片段

你可能感兴趣的:(iCode)