问题阐述
假设存在对象学生,学生中有主键,姓名,学生班级编码三个属性,如下:
@Data
public class Student{
private Long studentId;
private String studentName;
private String studentClazzCode;
private String studentClazzName;
}
对以上对象我们有以下几点说明:
- 主键[ studentId ]唯一
- 学生班级编码[ studentClazzCode ]为关联外键值,关联班级信息。为更好的说明问题我们假设以下班级信息,并且仅有以下班级信息:1[班级一];2[班级二];3[班级三]
- 学生班级名称[ studentClazzName ]为冗余值,为了方便辨认班级
让我们假设几条学生数据
public class test{
private static final List<Student> studentList = new ArrayList();
static{
studentList.add(newStudent(1L,"张三","1","班级一"));
studentList.add(newStudent(2L,"张四","1","班级一"));
studentList.add(newStudent(3L,"张五","2","班级二"));
studentList.add(newStudent(4L,"张六","2","班级二"));
studentList.add(newStudent(5L,"张七","3","班级三"));
studentList.add(newStudent(6L,"张八","3","班级三"));
}
private static Student newStudent(Long studentId,String studentName,String studentClazzCode,String studentClazzName){
Student student = new Student();
student.setStudentId(studentId);
student.setStudentName(studentName);
student.setStudentClazzCode(studentClazzCode);
student.setStudentClazzName(studentClazzName);
return student;
}
}
现在需要将学生按照班级编码分组并且每个分组是一个学生主键的列表。
简单的流分组可以将学生按照班级编码分组,但是每个分组内是一个学生的信息列表,如下:
Map<String,List<Student>> result = studentList.stream().collect(Collectors.groupingBy(Student::getStudentClazzCode);
解决问题方案
很明显,这需要在分组之后进行一次map操作,将学生信息转换为学生主键信息[及把Student转换为Long主键],这需要在分组之后进一步操作,当然也可以将Map中的每个列表取出来,在当前列表适用stream的map操作,如下:
result.get("1").stream().map(Student::getStudentId).collect(Collectors.toList());
但是这样会增加多一步操作,不管是在代码编写的简洁性和出于性能的考虑都不太合适,于是考虑groupingBy操作中有没有对结果进行后续处理的操作,找出了Collectors.mapping()函数,查阅源码发现它的方法签名如下:
public static <T, U, A, R>
Collector<T, ?, R> mapping(Function<? super T, ? extends U> mapper,
Collector<? super U, A, R> downstream);
方法存在两个参数:
- 参数1:mapper 这是对对象进行转换的函数,在这里你可以自定义对对象的转换,此处我们需要在Student中取出Long型主键
- 参数2: downstream 这是对处理结果的规约处理,在这里你可以对转换后的所有对象进行规约处理,此处我们需要把各个Long型主键规约成一个List集合
使用mapping()函数,我们可以吧代码简化成下面的:
Map<String,List<Long>> result = studentList.stream().collect(Collectors.groupingBy(Student::getStudentClazzCode,Collectors.mapping(Student::getStudentId,Collectors.toList()));
ok,最终的解决方案就是这样的,这种方式可以看到代码简洁到一行,不用再针对每个键值再对列表进行处理,而且由于流是Java内置的,所以在性能方面Java会对其进行优化
注意:代码并没有进行测试,在使用时请慎重
原文章地址请点击此处链接