Java 8嵌套(多级)组
我有几个类,如下
class Pojo { List items; } class Item { T key1; List subItems; } class SubItem { V key2; Object otherAttribute1; }
我想基于key1
聚合项目,对于每个聚合,子项应由key2
按以下方式聚合:
Map<T, Map<V, List>
如何使用Java 8 Collectors.groupingBy
嵌套?
我正在尝试一些东西并且中途停留
pojo.getItems() .stream() .collect( Collectors.groupingBy(Item::getKey1, /* How to group by here SubItem::getKey2*/) );
注意:这与级联groupingBy
,后者基于此处讨论的同一对象中的字段进行多级聚合
您不能通过多个键对单个项目进行分组,除非您接受该项目可能出现在多个组中。 在这种情况下,您想要执行一种flatMap
操作。
实现此目的的一种方法是使用Stream.flatMap
与一个临时对,在收集之前保存Item
和SubItem
的组合。 由于缺少标准对类型,典型的解决方案是使用Map.Entry
:
Map>> result = pojo.getItems().stream() .flatMap(item -> item.subItems.stream() .map(sub -> new AbstractMap.SimpleImmutableEntry<>(item, sub))) .collect(Collectors.groupingBy(e -> e.getKey().getKey1(), Collectors.mapping(Map.Entry::getValue, Collectors.groupingBy(SubItem::getKey2))));
不需要这些临时对象的替代方法是在收集器中执行flatMap
操作,但不幸的是,在Java 9之前, flatMapping
将不会出现。
有了它,解决方案看起来像
Map>> result = pojo.getItems().stream() .collect(Collectors.groupingBy(Item::getKey1, Collectors.flatMapping(item -> item.getSubItems().stream(), Collectors.groupingBy(SubItem::getKey2))));
如果我们不想等待Java 9,我们可能会在我们的代码库中添加一个类似的收集器,因为它实现起来并不难:
static Collector flatMapping( Function super T,? extends Stream extends U>> mapper, Collector super U,A,R> downstream) { BiConsumer acc = downstream.accumulator(); return Collector.of(downstream.supplier(), (a, t) -> { try(Stream extends U> s=mapper.apply(t)) { if(s!=null) s.forEachOrdered(u -> acc.accept(a, u)); }}, downstream.combiner(), downstream.finisher(), downstream.characteristics().toArray(new Collector.Characteristics[0])); }