Stream流之Collectors.toMap()方法详解
可以看到,这个方法可以有四个参数,前两个是必须的,我们可以清楚的理解前两个,一个是key,一个是value,最后一个其实是一个当 Key 冲突时调用的合并方法,最后一个是Map 构造器在需要返回特定的 Map 时使用,最后一个几乎很少使用。假设现在需求是返回一个list集合,那该怎么做呢,这个比较复杂,直接贴出代码。假设现在需求是返回老师底下的所有同学的最高分或者总分之类的应该怎么实现,一个简单的
目录
一:先贴出源码
Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper,
Function<? super T, ? extends U> valueMapper,
BinaryOperator<U> mergeFunction) {
return toMap(keyMapper, valueMapper, mergeFunction, HashMap::new);
}
单看源码可能概念比较模糊,索性直接通过几个例子来理解
二:前期准备->构建实体类
有两个实体类,Teacher和Student,使用一个老师底下有多个学生这个经典例子来解释,通过TeacherId这个字段来关联.
代码:
Teacher:
public class Teacher {
private Integer id;
private String name;
private List<Student> students;
public Teacher(Integer id, String name) {
this.id = id;
this.name = name;
}
@Override
public String toString() {
return "Teacher{" +
"id=" + id +
", name='" + name + '\'' +
", students=" + students +
'}';
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public List<Student> getStudents() {
return students;
}
public void setStudents(List<Student> students) {
this.students = students;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Student:
public class Student {
private Integer id;
private String name;
private Integer teacherId;
private Integer score;
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", teacherId=" + teacherId +
", score=" + score +
'}';
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getTeacherId() {
return teacherId;
}
public void setTeacherId(Integer teacherId) {
this.teacherId = teacherId;
}
public Integer getScore() {
return score;
}
public void setScore(Integer score) {
this.score = score;
}
public Student(Integer id, String name, Integer teacherId, Integer score) {
this.id = id;
this.name = name;
this.teacherId = teacherId;
this.score = score;
}
}
接下来构建几个老师和学生:
代码:
Teacher teacher = new Teacher(1,"李老师");
Teacher teacher1 = new Teacher(2,"马老师");
Teacher teacher2 = new Teacher(3,"王老师");
List<Teacher> teachers = new ArrayList<>();
teachers.add(teacher);
teachers.add(teacher1);
teachers.add(teacher2);
Student student = new Student(11,"张三", 1, 100);
Student student1 = new Student(12,"李四", 1, 90);
Student student2 = new Student(13,"王五", 1, 80);
Student student3 = new Student(14,"小明", 2, 98);
Student student4 = new Student(15,"李华", 2, 87);
Student student5 = new Student(16,"cxk", 3, 60);
List<Student> students = new ArrayList<>();
students.add(student);
students.add(student1);
students.add(student2);
students.add(student3);
students.add(student4);
students.add(student5);
三:方法解释
可以看到,这个方法可以有四个参数,前两个是必须的,我们可以清楚的理解前两个,一个是key,一个是value,最后一个其实是一个当 Key 冲突时调用的合并方法,最后一个是Map 构造器在需要返回特定的 Map 时使用,最后一个几乎很少使用
四:例子
1:简单的例子
// 第一个例子
Map<Integer, Student> collect = students.stream().collect(Collectors.toMap(Student::getTeacherId,Function.identity()));
Set<Integer> integers = collect.keySet();
Iterator<Integer> iterator = integers.iterator();
while (iterator.hasNext()) {
Integer next = iterator.next();
System.out.println("key:" +next+ " value:"+collect.get(next));
}
key为学生对应的老师Id,value为Function.identity()代表值是这个对象本身,运行主函数如下图
可以看到报错了,因为teacherId有多个,冲突了所以报错,这时候用到第三个参数了,可以把stream流改为
Map<Integer, Student> collect = students.stream().collect(Collectors.toMap(Student::getTeacherId,Function.identity(),(n1,n2)->n1));
这代表冲突是取第一个值,再测试一下
成功放回,这样可以猜测如果是(n1,n2)->n2时是返回最后一个值
2:较复杂的例子
假设现在需求是返回一个list集合,那该怎么做呢,这个比较复杂,直接贴出代码
students.stream().collect(Collectors.toMap(Student::getTeacherId,each -> Collections.singletonList(each),
(n1,n2)->{
List<Student> students1 = new ArrayList<>(n1);
students1.addAll(n2);
return students1;
}));
singletonList就是把对象转化为一个单例list,剩下的根据需求逻辑自行理解吧
测试一下
成功返回
其实如果需求是这样的话有个更简单的方法,
Map<Integer, List<Student>> collect2 = students.stream().collect(Collectors.groupingBy(Student::getTeacherId));
通过groupingBy来实现更清晰简单
3:复杂的例子
假设现在需求是返回老师底下的所有同学的最高分或者总分之类的应该怎么实现,
直接上代码:
总分:
Map<Integer, Integer> collect = students.stream().collect(Collectors.toMap(Student::getTeacherId, Student::getScore, (n1, n2) -> n1 + n2));
最高分:
Map<Integer, Integer> collect = students.stream().collect(Collectors.toMap(Student::getTeacherId, Student::getScore, (n1, n2) -> {
return n1>n2?n1:n2;
}));
最低分同理
五:实现业务
一个简单的业务就是查询老师的时候把这个老师底下的学生也顺带查出来
1:查底下所有学生
Map<Integer, List<Student>> collect3 = students.stream().collect(Collectors.groupingBy(Student::getTeacherId));
teachers.forEach(item->{
if(collect3.containsKey(item.getId())){
item.setStudents(collect3.get(item.getId()));
}
});
2:查底下分数最高的学生
Map<Integer, Student> collect4 = students.stream().collect(Collectors.toMap(Student::getTeacherId, Function.identity(), (n1, n2) -> {
return n1.getScore() > n2.getScore() ? n1 : n2;
}));
teachers.forEach(item->{
if(collect3.containsKey(item.getId())){
item.setStudents(collect3.get(item.getId()));
}
});
其他的业务自行根据逻辑处理
更多推荐
所有评论(0)