聚合两个以上的Java 8属性

时间:2017-02-10 13:54:21

标签: lambda java-8 sum field aggregate

非常简单,我有

 class Per{
    int a;
    long b;
    double c;
    String d;
}

假设我有3000个Per类型的对象,并收集在List<Per> pers

现在我想实现: -

  • 如果对象为空或dnullblank
  • ,请跳过
  • a
  • 的总和
  • b
  • 的总和
  • c
  • 执行的操作的汇总值
  

旧方式

int totalA = 0; long totalB = 0l; long totalC = 0l;
    for (Per per : pers) {
        if (per.d != null && !per.d.trim().equals("")) {
            totalA += per.a;
            totalB += per.b;
            totalC += someOperation(per.c);
        }
    }

someOperation实施并不重要,因为它可能很简单或复杂。

  

如何通过Java8流和lambda表达式实现这一目标?

可能的答案是这样的

int totalA = 0; long totalB=0l;
     pers.stream().filter(p->{
         if(p == null || p.d == null || p.d.trim().equals(""))
             return false;
         return true;
     }).forEach(per->{
         totalA += per.a;
            totalB += per.b;
     });

但是totalA和totalB必须是最终的或有效的最终

我心中的其他可能性是:

1使用Supplier作为suggested重复使用过滤后的流,然后应用地图和汇总操作。

2收集已过滤的Per,然后执行forEach

注意我未在此处进行任何类型的分组,无法创建新的Per或更新提供的对象。

1 个答案:

答案 0 :(得分:5)

编写自己的Accumulator课程和自定义Collector,然后这是一项简单的任务。

class Accumulator {
  private int a = 0;
  private long b = 0L;
  private double c = 0d;

  public void accumulate(Per p) {
    a += p.a;
    b += p.b;
    c += someOperation(p.c);
  }

  public Accumulator combine(Accumulator acc) {
    a += acc.a;
    b += acc.b;
    c += acc.c;
    return this;
  }
  // getter, hashCode, ...
}
Accumulator result = pers.stream()
    .filter(p -> p != null && p.d != null && !p.d.trim().isEmpty())
    .collect(Collector.of(Accumulator::new, Accumulator::accumulate, Accumulator::combine));