Collect stream into a HashMap with Lambda in Java 8

83,374

Solution 1

Seems that Collectors.toMap does not pick up the type arguments of stream.collect in your example and only returns a Map<Object,Object>.

As a workaround you can create the result map yourself and in the last stream step add the filtered entries to the result map:

Map<Set<Integer>, Double> result = new HashMap<>();
container.entrySet()
    .stream()
    .filter(entry -> entry.getKey().size() == size)
    .forEach(entry -> result.put(entry.getKey(), entry.getValue()));

Solution 2

If your ending map has a chance of "duplicate keys", there is a better solution using

toMap(Function<? super T, ? extends K> keyMapper,
                            Function<? super T, ? extends U> valueMapper,
                            BinaryOperator<U> mergeFunction,
                            Supplier<M> mapSupplier)

You could use it like this:

HashMap<Set<Integer>, Double> map = container.entrySet()
    .stream()
    .filter(k -> k.getKey().size() == size)
    .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (prev, next) -> next, HashMap::new));

Then as duplicate keys are added, it will use the latest instead of throwing an exception. The last parameter is optional.

If you want to keep duplicate keys into a list, then use Collectors.groupingBy instead.

Share:
83,374
chao
Author by

chao

Updated on May 08, 2021

Comments

  • chao
    chao about 3 years

    I have a HashMap which I need to filter using some function:

    HashMap<Set<Integer>, Double> container
    Map.Entry<Set<Integer>, Double> map = container.entrySet()
                .stream()
                .filter(k -> k.getKey().size() == size)
    

    For the size = 2 the following should be valid:

    containerBeforeFilter = {1,2,3} -> 1.5, {1,2} -> 1.3
    containerAfterFilter = {1,2} -> 1.3
    

    After I applied the function in the filter, I want to collect results again into a HashMap. However, when I try to apply the method suggested here, I'm getting illegal statements.

    So the following statement, applied after the filter, is illegal:

    .collect(Collectors.toMap((entry) -> entry.getKey(), (entry) -> entry.getValue()));
    

    What would be the proper way of collecting unchanged map values, where the only criteria is satisfying some key?

    UPDATE

    The mistake in the above code is the declared type of the variable map. It should have been Map rather than Map.Entry.

    So the now functional code is:

    Map<Set<Integer>, Double> map = container.entrySet()
                .stream()
                .filter(k -> k.getKey().size() == size)
                .collect(Collectors.toMap(entry -> entry.getKey(), entry -> entry.getValue()));