2

I have a MultivaluedMap and a list of strings, and I would like to see which of those string are keys in the MultivaluedMap. For each of the strings that are keys in the MultivaluedMap, I want to construct a new Thing out of the value of that key, set that string as a new key in a new HashMap<String, Thing>, and set the new Thing I've created as the value for that new key in the HashMap.

Right now, using a vanilla forEach, I have the following working solution:

MultivaluedMap<String, String> params = uriInfo.getQueryParameters();
HashMap<String, Thing> result = new HashMap<String, Thing>();

listOfStrings.forEach( (key) -> {
    String value = params.getFirst(key);
    if (value != null && !value.isEmpty()) {
        result.put(key, new Thing(value));
    }
});

However, I would like to implement a functional solution to this using the Java Stream API, and have attempted a fews solution. I have the following, which looks like it should work, but it does not:

MultivaluedMap<String, String> params = uriInfo.getQueryParameters();

HashMap<String, Thing> result = listOfStrings
        .stream()
        .filter(params::containsKey)
        .map( e -> new AbstractMap.SimpleEntry<String, Thing>(e, new Thing(params.getFirst(e))))
        .collect(Collectors.toMap(Entry::getKey, Entry::getValue));

The Entry::getKey and Entry::getValue are giving a "Non-static method cannot be referred from a static context". I've tried other variations of this: constructing the objects in keyMapper and valueMapper lambdas, and using reduce with an empty map as the initial value. None have worked.

How would I rewrite my first, working solution using the Java Stream API and aggregation (e.g. collect, reduce)? I have referenced this post and this post and this post.

Stefan Zobel
  • 3,182
  • 7
  • 28
  • 38
marinatedpork
  • 179
  • 1
  • 9

1 Answers1

2

Your code is fine. You just need to change the return type to Map instead of HashMap. If you need it to be HashMap specifically, you can pass HashMap::new into the factory overload.

One improvement I'd make is to cut out the unnecessary map() operation and do the lookup in the collector:

Map<String, Thing> result = listOfStrings
        .stream()
        .filter(params::containsKey)
        .collect(Collectors.toMap(Function.identity(), k -> new Thing(params.getFirst(k))));
shmosel
  • 49,289
  • 6
  • 73
  • 138