Java-Stream, toMap with duplicate keys

Problem statement: Converting SimpleImmutableEntry<String, List<String>> -> Map<String, List<String>>.

For Instance you have a SimpleImmutableEntry of this form [A,[1]], [B,[2]], [A, [3]] and you want your map to looks like this: A -> [1,3] , B -> [2].

This can be done with Collectors.toMap but Collectors.toMap works only with unique keys unless you provide a merge function to resolve the collision as said in java docs.

https://docs.oracle.com/javase/8/docs/api/java/util/stream/Collectors.html#toMap-java.util.function.Function-java.util.function.Function-java.util.function.BinaryOperator-

So the example code looks like this:

          .map(returnSimpleImmutableEntries)
          .collect(Collectors.toMap(SimpleImmutableEntry::getKey,
                                    SimpleImmutableEntry::getValue,
                                    (oldList, newList) -> { oldList.addAll(newList); return oldList; } ));

returnSimpleImmutableEntries method returns you entries of the form [A,[1]], [B,[2]], [A, [3]] on which you can use your collectors.


With Collectors.toMap:

Map<Long, Integer> abcIdToPmtId = paymentController.findPaymentsByIds(pmtIds)
    .stream()
    .collect(Collectors.toMap(
        Payment::getAbcId, 
        p -> new ArrayList<>(Arrays.asList(p.getPaymentId())),
        (o, n) -> { o.addAll(n); return o; }));

Though it's more clear and readable to use Collectors.groupingBy along with Collectors.mapping.

You don't need streams to do it though:

Map<Long, Integer> abcIdToPmtId = new HashMap<>();
paymentController.findPaymentsByIds(pmtIds).forEach(p ->
    abcIdToPmtId.computeIfAbsent(
            p.getAbcId(),
            k -> new ArrayList<>())
        .add(p.getPaymentId()));

Use the other groupingBy overload.

paymentController.findPaymentsByIds(pmtIds)
      .stream()
      .collect(
          groupingBy(Payment::getAbcId, mapping(Payment::getPaymentId, toList());