探索如何以最小的垃圾收集影响和最大的内存利用率创建堆外聚合。



java stream加法聚合 java数据聚合_java

使用Java Map,List和Object创建大型聚合通常会产生大量堆内存开销。 这也意味着,一旦聚合超出范围,垃圾收集器将必须清理这些对象。

阅读这篇简短的文章,了解如何使用Speedment Stream ORM创建堆外聚合,这些聚合可以更有效地利用内存,而对GC的影响很小或没有。

假设我们有大量具有以下形状的Person对象:

public class Person {
    private final int age;
    private final short height;
    private final short weight;        
    private final String gender;
    private final double salary;
    …
    // Getters and setters hidden for brievity
}

出于争论的目的,我们还可以访问一个名为persons()的方法,该方法将使用所有这些Person对象创建一个新的Stream

每年龄工资

我们要为每个年龄段创建平均工资。 为了表示汇总的结果,我们将使用称为AgeSalary的数据类,该数据类将某个年龄与平均工资相关联。

public class AgeSalary {
     private int age;
     private double avgSalary;
     … 
    // Getters and setters hidden for brievity
}

工资的年龄分组通常需要使用少于100个存储桶,因此此示例仅用于说明原理。 存储桶越多,聚集异常堆的意义就越大。

使用Speedment Stream ORM,我们可以通过以下三个步骤得出堆外聚合解决方案:

创建一个聚合器

var aggregator = Aggregator.builderOfType(Person.class, AgeSalary::new)
    .on(Person::age).key(AgeSalary::setAge)
    .on(Person::salary).average(AgeSalary::setAvgSalary)
    .build();

聚合器可以反复使用。

计算聚合

var aggregation = persons().collect(aggregator.createCollector());

使用聚合器,我们创建了一个标准的Java流收集器,其内部状态完全处于堆外。

使用汇总结果

aggregation.streamAndClose()
    .forEach(System.out::println);

由于聚合保存的是堆外存储的数据,因此可以从显式关闭中受益,而不仅仅是在很长时间之后才进行清理。 可以通过调用close()方法(可能是利用AutoCloseable特性close()来完成关闭聚合的操作,或者如上例所示,使用streamAndClose()返回流,该流将在流终止后关闭Aggregation

一站式服务

上面的代码可以简化为一种有效的代码:

persons().collect(Aggregator.builderOfType(Person.class, AgeSalary::new)
    .on(Person::age).key(AgeSalary::setAge)
    .on(Person::salary).average(AgeSalary::setAvgSalary)
    .build()
    .createCollector()
).streamAndClose()
    .forEach(System.out::println);

还支持并行聚合。 只需添加流操作Stream::parallel并使用ForkJoin池完成聚合。

资源资源

在此处下载Speedment

在此处阅读有关堆外聚合的更多信息

翻译自: https://www.javacodegeeks.com/2018/12/java-aggregate-data-heap.html