如何在forEach中执行操作并将其传递给Java流中的groupingBy

时间:2017-04-18 23:23:34

标签: java java-8 java-stream

我想根据某个决定划分我的清单。我还有一张存储这些决定的地图。 目前我正在更新流本身的决定。我觉得这不是一个好习惯,因为我正在使用收集来做 除了计算分组标准之外的其他操作。我的另一个选择是再次浏览流 并使用forEach更新地图,但这意味着我将使用getFinalDecision两次。有更好的方法吗?有办法吗? 我可以在forEach中执行getFinalDecision并将其传递给groupingBy?

val test = myList.stream().collect(groupingBy(t -> {
      A a = my_map.get(t.getSomething());
      A finalDecision = getFinalDecision(t.getSomeOtherThing(), a);
      my_map.put(t.getSomething(), finalDecision);
      return finalDecision;
}));

2 个答案:

答案 0 :(得分:3)

我不确定,但看起来你真正想做的更像是

Map<X,Y> result = myList.stream()
    .collect(groupingBy(t -> t.getSomething(),
         reducing(null, t -> t.getSomeOtherThing(), (a,b) -> getFinalDecision(b,a) )));

其中XgetSomething()的返回类型,YgetSomeOtherThing() resp的返回类型。 getFinalDecision(…)。当然,如果XY属于同一类型,它也可以使用。

这模仿原始代码中最初为空的映射的行为,导致null作为第二个参数传递给getFinalDecision,以便第一次出现每个不同的键。然后,第二个参数将是之前getFinalDecision对该键的评估结果。

可能是旧代码的行为只是妥协,所以我会提到替代方案。当你使用

Map<X,Y> result = myList.stream()
    .collect(groupingBy(t -> t.getSomething(), mapping(t -> t.getSomeOtherThing(),
        collectingAndThen(reducing((a,b) -> getFinalDecision(a,b)), Optional::get))));

该值最初将是对每个不同密钥的第一个getSomeOtherThing()调用的结果,并且只有在出现多个密钥时才会调用getFinalDecision。因此,第二个参数不会是null,除非getFinalDecision本身在之前的评估中返回null

答案 1 :(得分:0)

您可以使用Map#compute来简化代码:

test = myList.stream().collect(groupingBy(t -> my_map.compute(t.getSomething()
            ,(it, a) -> getFinalDecision(t.getSomeOtherThing(), a))));

使用Stream#peek&amp; Stream#collect描述它有两件事:合并&amp;&amp;的分组

test = myList.stream()
    .map(it -> new SimpleEntry<>(it, getFinalDecision(it.getSomeOtherThing()
                                           , my_map.get(it.getSomething()))))
    .peek(it-> my_map.put(it.getKey(),it.getValue()))
    .collect(groupingBy(SimpleEntry::getValue
                       ,mapping(SimpleEntry::getKey, toList())));