首页 > 解决方案 > 如何使用可选参数从 HashMap 中检索值

问题描述

我正在学习 Java 8 流,并且正在尝试重构一种方法。

假设我有一个 School 类和一个school map按 ID 存储所有学校对象的类。每个学校对象都包含一个student map存储一群学生的对象。

在这种情况下,学生 ID 在学校中是唯一的。

我有一个函数可以通过所有学校的 id 检索学生。

public Student getStudent(Map<String, School> schoolMap, String studentId) {
    return schoolMap.values().stream()
                             .map(School::getStudentIdToStudentMap)
                             .filter(map -> map.containsKey(studentId))
                             .map(map -> map.get(studentId))
                             .findAny().get();
}

现在,我想更改函数以schoolId用作过滤器(如果可用)。

public Student getStudent(Map<String, School> schoolMap, 
                          String schoolId /* can be null */, 
                          String studentId) 
{
    // TODO: Something that I have tried
    return schoolMap.get(schoolId)
                    .getStudentIdToStudentMap()
                    .get(studentId);
}

有没有一种好方法可以结合这两个功能?如果schoolId为空,则从所有学校获取学生。否则只是在特定学校查找并检索学生?

标签: javadictionaryjava-8hashmapjava-stream

解决方案


我敢打赌这就是你要找的东西:

public Student getStudent(Map<String, School> schoolMap, String schoolId, String studentId)
{
    return Optional.ofNullable(schoolId)             // schoolId might be null
          .map(id -> Stream.of(schoolMap.get(id)))   // get Stream<School> by  else
          .orElse(schoolMap.values().stream())       // ... get Stream of all Schools
          .flatMap(i -> i.getStudentIdToStudentMap() // students from 1/all schools ...
                         .entrySet().stream())       // flat map to Stream<Entry<..,..>>
          .collect(Collectors.toMap(                 // collect all entries bu key/value
              Entry::getKey, Entry::getValue))       // ... Map<String,Student> 
          .getOrDefault(studentId, null);            // get Student by id or else null
}

您必须搜索唯一已知的学校或所有学校。这个想法是基于搜索过程的共同特征。无论您迭代一所已知学校还是所有学校,任何学校的发现都保持不变。

或者List<Student>Optional,

public Student getStudent(Map<String, School> schoolMap, String schoolId, String studentId)
{
    return Optional.ofNullable(schoolId)                          // schoolId might be null
           .map(i -> Collections.singletonList(schoolMap.get(i))) // add School into List
           .orElse(new ArrayList<>(schoolMap.values()))           // ... else all schools
           .stream()
           .map(i -> i.getStudentIdToStudentMap()       // get Map of students from 1/all
                      .get(studentId))                  // ... find by studentId
           .filter(Objects::nonNull)                    // get rid of nulls
           .findFirst().orElse(null);                   // get Student by id or else null
}

推荐阅读