我的班有两个领域:
> MyKey – 我想分组的关键
>设置< MyEnum> – 我想要展平和合并的集合.
我有一个这样的对象列表,我想要的是获得一个Map< MyKey,Set< MyEnum>其中的值是使用此键从对象的所有myEnums连接的.
例如,如果我有三个对象:
> myKey:key1,myEnums:[E1]
> myKey:key1,myEnums:[E2]
> myKey:key2,myEnums:[E1,E3]
预期结果应该是:
key1 => [E1,E2],key2 => [E1,E3]
我想出了这段代码:
Map> map = myObjs.stream()
.collect(Collectors.groupingBy(
MyType::getMyKey,
Collectors.reducing(
new HashSet(),
MyType::getMyEnums,
(a, b) -> {
a.addAll(b);
return a;
})));
它有两个问题:
>减少内部的HashSet似乎在所有键之间共享.这就是说上面例子的实际运行结果是key1 => [E1,E2,E3],key2 => [E1,E2,E3].为什么会这样?
>即使这段代码有效,它看起来也很难看,尤其是在减少我必须手动处理构建连接集合的逻辑的部分.有没有更好的方法呢?
谢谢!
最佳答案:
请注意,您只创建一个标识对象:new HashSet< MyEnum>().
您作为第三个参数提供的BinaryOperator必须是idempotent,与常见的数学运算符相同,例如x = y z不会改变y和z的值.
这意味着您需要合并两个输入集a和b,而不更新任何一个.
此外,使用枚举,您应该使用EnumSet,而不是HashSet.
Map> map = myObjs.stream()
.collect(Collectors.groupingBy(
MyType::getMyKey,
Collectors.reducing(
EnumSet.noneOf(MyEnum.class), //
MyType::getMyEnums,
(a, b) -> {
EnumSet c = EnumSet.copyOf(a); //
c.addAll(b);
return c;
})));
UPDATE
更短,更简化的版本,在累积结果时不必继续创建新集:
Map> map = myObjs.stream()
.collect(Collectors.groupingBy(
MyType::getMyKey,
Collector.of(
() -> EnumSet.noneOf(MyEnum.class),
(r, myObj) -> r.addAll(myObj.getMyEnums()),
(r1, r2) -> { r1.addAll(r2); return r1; }
)));
标签:java,java-8,collectors
来源: https://codeday.me/bug/20190516/1115007.html