Java 8 - 如何对列表映射中的所有List元素求和

hor*_*rus 6 lambda java-8 java-stream

我有一个特定对象的列表映射,我想基于特定的实例变量添加列表的所有元素.

我的对象:

class Risk{ 
    Integer id, riskValue, totRisk=0;
    String name;

    Integer getId(){
       return id;
    }
    Risk(Object[] result){
         id=(Integer)result[0];
         riskValue=(Integer)result[1];
         name=(String)result[3];
    }
}
Run Code Online (Sandbox Code Playgroud)

我从数据库中获得了一个类型为对象的数组列表:

List< Object[] > results=getResults();
Run Code Online (Sandbox Code Playgroud)

我使用Java 8组我的数据由ID,因为我想SUMriskValue类型的所有对象Risk具有相同id.

这就是我做的:

List<Risk> risks=results.stream().map(Risk::new).collect(Collectors.toList());
Map<Integer, List<Risk>> byId=risks.stream.collect(Collectors.groupingBy(Risk::getId));
Run Code Online (Sandbox Code Playgroud)

此时,我将所有Risk对象按ID分组.并且我希望每个列表总结所有对象riskValue并在变量中包含总数totRisk

如何在变量中计算每个List中变量totRisk的总和riskValue

注1:我想用Java 8做,我知道如何使用Java 7及以下版本.

注2:也许它也可以一次完成,因为没有先按ID分组.我想要实现的是将原始中具有相同ID的所有对象相加List<Object[]> results.如果只用一个语句就可以做到更好.

Hol*_*ger 7

你必须要知道你可以结合Collectors.看到Collectors.groupingBy(Function,Collector)

Map<Integer, Integer> byId=risks.stream.collect(
    Collectors.groupingBy(Risk::getId, Collectors.summingInt(Risk::getRiskValue)));
Run Code Online (Sandbox Code Playgroud)

您还可以将其与第一个操作组合:

Map<Integer, Integer> byId=results.stream().map(Risk::new).collect(
    Collectors.groupingBy(Risk::getId, Collectors.summingInt(Risk::getRiskValue)));
Run Code Online (Sandbox Code Playgroud)

请注意,我假设getRiskValue()您的类中有一个方法Risk,否则您必须Risk::getRiskValue使用lambda表达式替换r -> r.riskValue才能访问该字段,但是,始终建议使用getter方法.

结果从id映射到total.


重读你的问题后,我注意到,你实际上要总结riskValue并存储内totRisk每个(?)Risk的实例.这有点复杂,因为它不适合常见的使用模式:

Map<Integer, List<Risk>> byId=results.stream().map(Risk::new).collect(
  Collectors.groupingBy(Risk::getId, Collectors.collectingAndThen(
    Collectors.toList(), l-> {
      int total=l.stream().collect(Collectors.summingInt(r -> r.riskValue));
      l.forEach(r->r.totRisk=total);
      return l;
    })));
Run Code Online (Sandbox Code Playgroud)

在这一点上我们真的应该切换到使用import static java.util.stream.Collectors.*;:

Map<Integer, List<Risk>> byId=results.stream().map(Risk::new).collect(
  groupingBy(Risk::getId, collectingAndThen(toList(), l-> {
    int total=l.stream().collect(summingInt(r -> r.riskValue));
    l.forEach(r->r.totRisk=total);
    return l;
  })));
Run Code Online (Sandbox Code Playgroud)