Ignore duplicates when producing map using streams Ignore duplicates when producing map using streams java java

Ignore duplicates when producing map using streams


This is possible using the mergeFunction parameter of Collectors.toMap(keyMapper, valueMapper, mergeFunction):

Map<String, String> phoneBook =     people.stream()          .collect(Collectors.toMap(             Person::getName,             Person::getAddress,             (address1, address2) -> {                 System.out.println("duplicate key found!");                 return address1;             }          ));

mergeFunction is a function that operates on two values associated with the same key. adress1 corresponds to the first address that was encountered when collecting elements and adress2 corresponds to the second address encountered: this lambda just tells to keep the first address and ignores the second.


As said in JavaDocs:

If the mapped keys contains duplicates (according to Object.equals(Object)), an IllegalStateException is thrown when the collection operation is performed. If the mapped keys may have duplicates, use toMap(Function keyMapper, Function valueMapper, BinaryOperator mergeFunction) instead.

So you should use toMap(Function keyMapper, Function valueMapper, BinaryOperator mergeFunction) instead. Just provide a merge function, that will determine which one of duplicates is put in the map.

For example, if you don't care which one, just call

Map<String, String> phoneBook =         people.stream()              .collect(Collectors.toMap(Person::getName,                                         Person::getAddress,                                         (a1, a2) -> a1));


The @alaster answer help me a lot, but I would like to add a meaninful information if someone is trying to group the information.

If you have, per example, two Orders with the same code but different quantity of products for each one, and your desire is sum the quantities, you can do:

List<Order> listQuantidade = new ArrayList<>();listOrders.add(new Order("COD_1", 1L));listOrders.add(new Order("COD_1", 5L));listOrders.add(new Order("COD_1", 3L));listOrders.add(new Order("COD_2", 3L));listOrders.add(new Order("COD_3", 4L));listOrders.collect(Collectors.toMap(Order::getCode,                                     o -> o.getQuantity(),                                     (o1, o2) -> o1 + o2));

Result:

{COD_3=4, COD_2=3, COD_1=9}

Or from the javadocs combine addresses:

 Map<String, String> phoneBook     people.stream().collect(toMap(Person::getName,                                   Person::getAddress,                                   (s, a) -> s + ", " + a));