0

How to handle exception while duplicate in map with Lamda.

List<Person> person = Arrays.asList(
                new Person("Charles","Dickens",60),
                new Person("Dickens","Charles",60),
                new Person("Lewis","Charles",60),
                new Person("Charles","Dickens",60),
                new Person("abc","abc",20));;

            //applying toMap to collect 
        Map<Object, Object> peronMap = person.stream().limit(5)
                        .collect(Collectors.toMap(Person::getName,Person::getAge));

        System.out.println(peronMap);

this is my list

but I am getting an error

Exception in thread "main" java.lang.IllegalStateException: Duplicate key 60
    at java.util.stream.Collectors.lambda$throwingMerger$0(Unknown Source)
    at java.util.HashMap.merge(Unknown Source)
    at java.util.stream.Collectors.lambda$toMap$58(Unknown Source)
    at java.util.stream.ReduceOps$3ReducingSink.accept(Unknown Source)
    at java.util.stream.SliceOps$1$1.accept(Unknown Source)
    at java.util.Spliterators$ArraySpliterator.tryAdvance(Unknown Source)
    at java.util.stream.ReferencePipeline.forEachWithCancel(Unknown Source)
    at java.util.stream.AbstractPipeline.copyIntoWithCancel(Unknown Source)
shiv
  • 477
  • 5
  • 17

1 Answers1

2

You can use the overloaded version of Collectors.toMap which takes a third parameter mergeFunction from the Java Docs:

If the mapped keys contains duplicates (according to Object.equals(Object)), the value mapping function is applied to each equal element, and the results are merged using the provided merging function.

Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper,
                                Function<? super T, ? extends U> valueMapper,
                                BinaryOperator<U> mergeFunction)

The third parameter of BinaryOperator resolves the merge error if there is a duplicate key :

Map<Object, Object> peronMap = person.stream().limit(5)
                    .collect(Collectors.toMap(Person::getName,
                                              Person::getAge, 
                                              (age1, age2) -> age2));

In the above code the last parameter is the BinaryOperator which takes the second value if there is a duplicate key and ignores the first one.

For example in your data, there are two duplicates new Person("Dickens","Charles",60) and again new Person("Charles","Dickens",60), so when the Map is created from the Person stream there would be a merge error as the key is same for the two objects. If the third parameter which is a mergeFunction is supplied you are telling how to resolve the merge error.

In my sample code it will take the second value if there are two keys with the same name.

If the data would have been: new Person("Charles","Dickens",60) and new Person("Charles","Dickens",61), the key is same Charles but if you use my code the second value of 61 would be considered and the first value of 60 will be discarded in the final Map.

Fullstack Guy
  • 16,368
  • 3
  • 29
  • 44