5
\$\begingroup\$

I have a Map<String, List<Object>> multiFieldMap and I need to iterate over its value set and add the value to multiFieldsList:

public List<Object> fetchMultiFieldsList() {
    List<Object> multiFieldsList = new ArrayList<>();
    for (Entry<String, List<Object>> entry : multiFieldMap.entrySet()) {
        String entityName = entry.getKey();
        List<Object> ids = entry.getValue();
        for (Object id : ids) {
            Object entity = queryService.query(entityName, queryService.property("id").eq(id));
            multiFieldsList.add(entity);
        }
    }
    return multiFieldsList;
}

Can this method be simplified further?

\$\endgroup\$
6
\$\begingroup\$

You can accomplish this using Java 8 streams.

public List<Object> fetchMultiFieldsList() {
    return multiFieldMap.entrySet().stream()
      .flatMap(e -> {
          String entityName = e.getKey();
          List<Object> ids = e.getValue();
          return ids.stream()
            .map(id -> queryService.query(entityName, queryService.property("id").eq(id)));
      }).collect(Collectors.toList());
}

I think the code itself is relatively self-explanatory. The important bit is the usage of flatMap instead of map for the first mapping operation so that the resulting streams are concatenated, ending up with a flat list of objects rather than a list of lists.

It is unfortunate that Java does not support destructuring assignment, which would allow the first lambda expression to be a single expression of the form (k, v) -> ..., but it does not, so I've left the statements in for clarity.

If you are willing to omit the inner declarations, the above code can be simplified further.

public List<Object> fetchMultiFieldsList() {
    return multiFieldMap.entrySet().stream()
      .flatMap(e -> e.getValue().stream()
          .map(id -> queryService.query(e.getKey(), queryService.property("id").eq(id)))
      ).collect(Collectors.toList());
}

Whichever one you prefer is a matter of personal preference. The former has more descriptive variable names, while the latter is simpler and more functional.

\$\endgroup\$
1
\$\begingroup\$

You could replace the map with a multimap. Using Google's Guava Multimap, you don't need the nested loop / flatMap():

private Multimap<String, Object> multiFieldMap = ArrayListMultimap.create();

public List<Object> fetchMultiFieldsList() {
    return multiFieldMap.entries().stream()
        .map(e -> queryService.query(e.getKey(),
                      queryService.property("id").eq(e.getValue())))
        .collect(Collectors.toList());
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.