Java8 stream.collect(…groupingBy(…映射(…减少)))减少二进制运算符的使用

Java8 stream.collect(…groupingBy(…映射(…减少)))减少二进制运算符的使用,java,java-8,java-stream,collectors,Java,Java 8,Java Stream,Collectors,我使用groupingBy、mapping和reduce 请回答以下问题:。我们的目标是得到一张以年龄为关键,以个人爱好为集的地图 我提出的一个解决方案(不好,但这不是重点)有一个奇怪的行为 将以下列表作为输入: List<Person> personList = Arrays.asList( new Person(/* name */ "A", /* age */ 23, /* hobbies */ asList("a")), new Person("BC",

我使用
groupingBy
mapping
reduce
请回答以下问题:。我们的目标是得到一张以年龄为关键,以个人爱好为集的地图

我提出的一个解决方案(不好,但这不是重点)有一个奇怪的行为

将以下列表作为输入:

List<Person> personList = Arrays.asList(
     new Person(/* name */ "A", /* age */ 23, /* hobbies */ asList("a")),
     new Person("BC", 24, asList("b", "c")),
     new Person("D", 23, asList("d")),
     new Person("E", 23, asList("e"))
);
显然不是我所期望的。我倒是预料到了这一点:

map = {23=[a, d, e], 24=[b, c]}
现在,如果我只是将二进制运算符(归约收集器)的
(strings,strings2)
的顺序替换为
(strings2,strings)
,我就得到了预期的结果。我错过了什么? 我是否误解了
减少
-收集器?或者,我遗漏了哪一篇文档,这篇文档清楚地表明我的使用没有按预期工作

Java版本是1.8.0_121,如果这很重要的话。

缩减不应该修改传入的对象。在您的例子中,您正在修改传入的
HashSet
,它应该是标识值并返回它,因此所有组都将有相同的
HashSet
实例作为结果,包含所有值

您需要的是一个,它可以通过(…)
收集器实现,就像它已经通过预构建的收集器
收集器.toList()
收集器.toSet()等实现一样

Map<Integer, Set<String>> map = personList.stream()
    .collect(Collectors.groupingBy(o -> o.age,
        Collector.of(HashSet::new, (s,p) -> s.addAll(p.hobbies), (s1,s2) -> {
            s1.addAll(s2);
            return s1;
        })));

有意思。。起初,我甚至试图在
收集器中找到
flatMapping
(或者应用
嗜好.stream()
并使用它)。很高兴知道它就要来了。哦,天哪,我把合路器和接线员弄混了。所以,这只是一个巧合,切换参数会产生正确的结果。谢谢你的澄清!是的,在顺序上下文中,缩减函数将始终作为
f(上一个,下一个)
进行计算,而
previous
将作为第一次计算的标识值和后续计算的上一个结果。因此
(a,b)->a
将始终以标识值结束,而
(a,b)->b
将使用映射器函数创建的新集合。但是在并行计算中,两个参数都可以是前一个部分计算的结果,并且由于部分结果可以为空,因此两个参数都可以是标识值,因此使用第二个参数不是可靠的解决方案。
map = {23=[a, d, e], 24=[b, c]}
Map<Integer, Set<String>> map = personList.stream()
    .collect(Collectors.groupingBy(o -> o.age,
        Collector.of(HashSet::new, (s,p) -> s.addAll(p.hobbies), (s1,s2) -> {
            s1.addAll(s2);
            return s1;
        })));
Map<Integer, Set<String>> map = personList.stream()
    .collect(Collectors.groupingBy(o -> o.age,
        Collectors.flatMapping(p -> p.hobbies.stream(), Collectors.toSet())));