Статьи

Java: агрегирование данных вне кучи

Узнайте, как создавать агрегации вне кучи с минимальным воздействием сбора мусора и максимальным использованием памяти.

агрегация вне кучи

Создание больших агрегатов с использованием Java Map, List и Object обычно создает много накладных расходов кучи памяти. Это также означает, что сборщик мусора должен будет очистить эти объекты после того, как агрегация выйдет из области видимости.

Прочтите эту небольшую статью и узнайте, как мы можем использовать Speedment Stream ORM для создания агрегаций вне кучи, которые могут использовать память более эффективно и практически без влияния ГХ.

Человек

Допустим, у нас есть большое количество объектов Person которые принимают следующую форму:

1
2
3
4
5
6
7
8
9
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
}

Ради аргумента, у нас также есть доступ к методу Person persons() , который создаст новый Stream со всеми этими объектами Person .

Зарплата за возраст

Мы хотим создать среднюю зарплату для каждого возраста. Для представления результатов агрегации мы будем использовать класс данных с именем AgeSalary который связывает определенный возраст со средней зарплатой.

1
2
3
4
5
6
public class AgeSalary {
     private int age;
     private double avgSalary;
     
    // Getters and setters hidden for brievity
}

Возрастная группировка по зарплатам обычно предполагает использование менее 100 групп, поэтому этот пример просто демонстрирует принцип. Чем больше сегментов, тем больше смысла собирать вне кучи.

Решение

Используя Speedment Stream ORM, мы можем получить решение агрегации вне кучи с помощью следующих трех шагов:

Создать агрегатор

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

Агрегатор можно использовать снова и снова.

Вычислить агрегацию

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

Используя агрегатор, мы создаем стандартный поток Java Collector, у которого его внутреннее состояние полностью вне кучи.

Используйте результат агрегации

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

Поскольку агрегация хранит данные, которые хранятся вне кучи, она может выиграть от явного закрытия, а не от простой очистки потенциально намного позже. Закрытие агрегации можно выполнить, вызвав метод close() , возможно, воспользовавшись признаком AutoCloseable , или, как в примере выше, с помощью streamAndClose() который возвращает поток, который закроет Aggregation после завершения потока.

Все в одну строчку

Приведенный выше код может быть сведен к одной строке:

1
2
3
4
5
6
7
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 пула ForkJoin .

Ресурсы

Скачать Speedment здесь

Подробнее об агрегации вне кучи читайте здесь

См. Оригинальную статью здесь: Java: агрегирование данных вне кучи

Мнения, высказанные участниками Java Code Geeks, являются их собственными.