How to retrieve a value from HashMap with optional argument

SyncMaster :

I am learning Java 8 streams and I am trying to refactor a method.

Say I have a School class and a school map that stores all school objects by Id. Each school object contains a student map that stores a bunch of students.

In this scenario, the student Ids are unique across the schools.

I have a function that retrieves a student by the id across all schools.

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();
}

Now, I want to change the function to use schoolId as a filter if available.

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);
}

Is there a good way I can combine these two functions? If schoolId is null, get the student from all schools. Else just lookup in the particular school and retrieve the student?

Nikolas :

I bet this is what are you looking for:

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
}

You have to search in either the only known school or in all the schools. The idea is based on the common characteristics of the searching process. The finding in any school remains the same regardless you iterate one known school or all the ones.

Alternatively get List<Student> from 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
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=76028&siteId=1