业务背景
假设当前有一个对学生进行各方面评价的对象,评价包括考察模块、考察点、评价备注。字段关系为,同一模块包含多个考察点,每个考察点有一个评价备注。
对象代码如下
@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);
}
这里我们把创建的测试对象集合打印出来(控制台打印信息如下)
看图我们可以更加直观地看到我们数据是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来收集的,所以打乱了原本的顺序。
查看源码我们也能看出来,groupingBy默认使用HashMap来收集数据。因此我们只需要把HashMap换成LinkedHashMap即可解决这个问题。
通过阅读源码我们也能看到,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()));
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);
}
运行结果如下
完整的代码片段在这里 码云代码片段