我有学生名单。
我想返回具有该类(class)的对象StudentResponse类的列表以及该类(class)的学生列表。
所以我可以写给我一张 map

Map<String, List<Student>> studentsMap = students.stream().
            .collect(Collectors.groupingBy(Student::getCourse,
                    Collectors.mapping(s -> s, Collectors.toList()
             )));

现在,我必须再次遍历 map 以创建具有类(class)和列表的StudentResponse类的对象列表:
class StudentResponse {
     String course;
     Student student;

     // getter and setter
}

有没有办法结合这两个迭代?

最佳答案

并非完全符合您的要求,但这是一种紧凑的方法来完成您想要的内容,只是为了保持完整性:

Map<String, StudentResponse> map = new LinkedHashMap<>();
students.forEach(s -> map.computeIfAbsent(
        s.getCourse(),
        k -> new StudentResponse(s.getCourse()))
    .getStudents().add(s));

假设StudentResponse具有构造函数,该构造函数将类(class)作为参数接受并且是学生列表的 getter ,并且该列表是可变的(即ArrayList),以便我们可以向其添加当前学生。

虽然上述方法有效,但显然违反了基本的OO原则,即封装。如果您对此表示满意,那么您就完成了。如果要遵守封装,则可以在StudentResponse中添加一个方法来添加Student实例:
public void addStudent(Student s) {
    students.add(s);
}

然后,解决方案将变为:
Map<String, StudentResponse> map = new LinkedHashMap<>();
students.forEach(s -> map.computeIfAbsent(
        s.getCourse(),
        k -> new StudentResponse(s.getCourse()))
    .addStudent(s));

这种解决方案显然比以前的解决方案更好,并且可以避免遭到认真的代码审查者的拒绝。

两种解决方案都依赖Map.computeIfAbsent,后者为提供的类(class)返回StudentResponse(如果在 map 中存在该类(class)的条目),或者创建并返回以类(class)为参数构建的StudentResponse实例。然后,将学生添加到返回的StudentResponse的学生的内部列表中。

最后,您的StudentResponse实例位于 map 值中:
Collection<StudentResponse> result = map.values();

如果您需要List而不是Collection:
List<StudentResponse> result = new ArrayList<>(map.values());

注意:我使用的是LinkedHashMap而不是HashMap来保留插入顺序,即学生在原始列表中的顺序。如果您没有这样的要求,请使用HashMap

09-11 19:56