Самое чистое решение - определить собственный коллектор:
Map<Long, Set<Payment>> result = rowData.stream()
.collect(Collectors.groupingBy(
ReportData::getCaseId,
Collector.of(HashSet::new,
(s, r) -> s.addAll(r.getRuling().getPayments()),
(s1, s2) -> { s1.addAll(s2); return s1; })
));
Два других решения, о которых я подумал вначале, но на самом деле они менее эффективны и читабельны, но при этом избегают создания промежуточного звена Map
:
Объединение внутренних наборов с использованием Collectors.reducing()
:
Map<Long, Set<Payment>> result = rowData.stream()
.collect(Collectors.groupingBy(
ReportData::getCaseId,
Collectors.reducing(Collections.emptySet(),
r -> r.getRuling().getPayments(),
(s1, s2) -> {
Set<Payment> r = new HashSet<>(s1);
r.addAll(s2);
return r;
})
));
, где операция reducing
объединит Set<Payment>
записей с одинаковыми caseId
.Это, однако, может привести к большому количеству копий наборов, если вам нужно много слияний.
Другое решение - с нисходящим коллектором, который отображает вложенные коллекции:
Map<Long, Set<Payment>> result = rowData.stream()
.collect(Collectors.groupingBy(
ReportData::getCaseId,
Collectors.collectingAndThen(
Collectors.mapping(r -> r.getRuling().getPayments(), Collectors.toList()),
s -> s.stream().flatMap(Set::stream).collect(Collectors.toSet())))
);
По сути, этообъединяет все наборы совпадающих caseId
в List
, а затем отображает этот список в один Set
.