1

I get an PublicException: Duplicate Keys error in this place.

Map<BgwContract, List<Fee>> bgwContractFeeMap = bgwContractList
            .stream()
            .filter(bgwContract -> !bgwContract.getStatus().equals(BgwContractStatus.CLOSED))
            .filter(bgwContract -> availableIbans.contains(bgwContract.getFeeAccount()))
            .collect(
                    Collectors.toMap(bgwContract -> bgwContract,
                                     bgwContractFeeService::getContractMonthlyFees)
            );

I understand that the issue is that there are some duplicates and it immediately crashes. I know that a .distinct() would fix this error, but I don't want to lose any data. Is there a way how to enhance this mapping to fix this error without loosing any values, maybe some kind of a filter or any other kind of java 8 methods? I'm not talking about MultiMaps etc.

developer1
  • 527
  • 4
  • 27
  • Does this answer your question? [Ignore duplicates when producing map using streams](https://stackoverflow.com/questions/32312876/ignore-duplicates-when-producing-map-using-streams) – Amit Bera Nov 07 '19 at 09:05
  • @AmitBera I believe that by ignoring the second key(duplicate) it also ignores the value that the second key was mapped to, and I don't want to lose that. – developer1 Nov 07 '19 at 09:25

1 Answers1

1

You need to pass a merge function to Collectors.toMap(), which handles values having the same key:

Map<BgwContract, List<Fee>> bgwContractFeeMap = bgwContractList
            .stream()
            .filter(bgwContract -> !bgwContract.getStatus().equals(BgwContractStatus.CLOSED))
            .filter(bgwContract -> availableIbans.contains(bgwContract.getFeeAccount()))
            .collect(
                    Collectors.toMap(Function.identity(),
                                     bgwContractFeeService::getContractMonthlyFees,
                                     (l1,l2)->{
                                         l1.addAll(l2);
                                         return l1;
                                      })
            );

In this case, the elements of two value lists having the same key will be concatenated into a single list.

Eran
  • 387,369
  • 54
  • 702
  • 768
  • Yes, exactly what I was looking for, just couldn't figure how to google for this solution! – developer1 Nov 07 '19 at 09:10
  • But now in `l1.addAll(l2);` I get null and it still crashes. Could you please suggest how to deal with that without losing any data? – developer1 Nov 07 '19 at 09:23
  • 2
    @Martin does it mean that `getContractMonthlyFees()` might be returning `null` in some cases? Can you change it to return an empty List instead? – Eran Nov 07 '19 at 09:25
  • Could be, I'll try and let you know – developer1 Nov 07 '19 at 09:42
  • Found the problem, and somehow solved it. the method returned `Collections.singletonList(feeService.getFeeByFeeName(feeName));` I changed it to `List feeList = new ArrayList<>(); feeList.add(feeService.getFeeByFeeName(feeName)); return feeList;` and the problem dissapeared. I just don't understand why? – developer1 Nov 07 '19 at 10:29
  • 1
    @Martin both `Collections.singletonList()` and `Arrays.asList()` won't do, since both have a fixed length, so you can't add elements to them. You either have to return a mutable `List` from your method, or create a new ArrayList in the merge function. – Eran Nov 07 '19 at 10:32
  • 1
    @Martin or you can change `bgwContractFeeService::getContractMonthlyFees` to `c -> new ArrayList<>(bgwContractFeeService.getContractMonthlyFees(c))`; – Eran Nov 07 '19 at 10:34
  • Oh, so that's why it crashed because it tried to add to `Collections.singletonList()` – developer1 Nov 07 '19 at 10:38
  • changed to `new ArrayList<>(Arrays.asList(feeService.getFeeByFeeName(feeName)));` – developer1 Nov 07 '19 at 11:07
  • @Martin I thought `feeService.getFeeByFeeName(feeName)` returns a List (this is implied by the code in your question), so why do you need to wrap it with `Arrays.asList()`? Did you change the method to return an array? – Eran Nov 07 '19 at 11:09