-1

I have a Collection of Strings which I want to iterate and do a DB query on each of them and collect the response of each query into a Collection of Objects. I am sure we can do this through a for loop iterator but is there a way to do it with Java8 Streams ? This is what I came up with -

static Collection<Action> getActions(Collection<String> actionIds, RequestContext rc) {
    List<Collection<Action>> ac = actionIds.stream().map(str -> hashmap.get(str)).collect(Collectors.toList());
    
    return ac.get(0);
}

Action is a custom class. I read that I may need to do something like this - https://itsallbinary.com/java-8-create-custom-streams-collector/ .
Is this necessary ? Or any easier ways ?

If I use this .collect(toCollection(ArrayList::new)), it gives me Collection<Collection<Action>>

Nowhere Man
  • 19,170
  • 9
  • 17
  • 42
Harrish A
  • 53
  • 8
  • Nope. I need a Collection. And I cannot do new Collection(); – Harrish A Jan 19 '22 at 09:44
  • If I use this .collect(toCollection(ArrayList::new)) it gives me Collection> – Harrish A Jan 19 '22 at 10:01
  • Does `hashmap.get(str)` return a `Collection` of `Action`s (it seems so)? – Markus Ratzer Jan 19 '22 at 10:07
  • @MarkusRatzer yes, it does. If I remove .collect() completely. It says required Collection but provided Stream – Harrish A Jan 19 '22 at 10:12
  • You _could_ use `...flatMap(str -> hashmap.get(str).stream()).collect(...)` (instead of `...map(...).collect(...)`), but that _might_ not be correct from a business logic point of view. Alternatively `...map(str -> hashmap.get(str).flatMap(Collection::stream).collect(...)` which is more readible to some people. – Markus Ratzer Jan 19 '22 at 10:16

1 Answers1

0

It seems that hashmap is a Map<String, Collection<Action>> which can be converted into filtered Collection<Action> using Stream::flatMap, as suggested in the comments.

Possibly it's worth to filter available actionIds as a defensive measure. Also, some specific implementation of the collection needs to be selected or at least Set or List depending on the actual requirements (e.g. if the order of the actions needs to be maintained, or if the duplicate actions need to be filtered, etc.)

Most likely, a mere Collectors::toList would be fine for the result:

static Collection<Action> getActions(Collection<String> actionIds, RequestContext rc) {
    return actionIds.stream()
        .filter(hashmap::containsKey) // make sure nulls not returned
        .map(hashmap::get) // Stream<Collection<Action>>
        .flatMap(Collection::stream) // Stream<Action>
        .collect(Collectors.toList()); // List<Action>
}

"Unique" values may be retrieved using Stream::distinct before collecting to list or by collecting to a set instead of list (using LinkedHashSet to maintain the order of insertion):

static Collection<Action> getDistinctActions(Collection<String> actionIds, RequestContext rc) {
    return actionIds.stream()
        .filter(hashmap::containsKey) // make sure nulls not returned
        .flatMap(actions -> actions.stream()) // Stream<Action>
        .collect(Collectors.toCollection(LinkedHashSet::new));
}
Nowhere Man
  • 19,170
  • 9
  • 17
  • 42