То, что вы пытаетесь сделать, называется операцией «сворачивания» в функциональном программировании. Потоки Java называют это «сокращение» и «сумма», «счет» и т. Д. c. просто специализированные складки / складки. Вам просто нужно предоставить двоичную функцию накопления. Я предполагаю Java геттеры и сеттеры стиля Bean и конструктор всех аргументов. Мы просто игнорируем другие поля объекта в нашем накоплении:
List<MyObj> data = fetchData();
Date d = new Date();
MyObj res = data.stream()
.reduce((a, b) -> {
return new MyObj(0, a.getEmployee(),
a.getInCount() + b.getInCount(), // Accumulate IN_COUNT
a.getOutCount() + b.getOutCount(), // Accumulate OUT_COUNT
d);
})
.orElseThrow();
Это упрощено и предполагает, что у вас есть только один сотрудник в списке, но вы можете использовать стандартные операции с потоком для разделения и группировки вашего потока (groupBy).
Если вы не хотите или не можете создавать MyObj, вы можете использовать другой тип в качестве аккумулятора. Я буду использовать Map.entry
, потому что Java не имеет типа Pair / Tuple:
Map.Entry<Integer, Integer> res = l.stream().reduce(
Map.entry(0, 0), // Identity
(sum, x) -> Map.entry(sum.getKey() + x.getInCount(), sum.getValue() + x.getOutCount()), // accumulate
(s1, s2) -> Map.entry(s1.getKey() + s2.getKey(), s1.getValue() + s2.getValue()) // combine
);
Что здесь происходит? Теперь у нас есть функция уменьшения Pair accum, MyObj next -> Pair
. «Идентичность» - это наше начальное значение, функция накопителя добавляет следующий MyObj к текущему результату, а последняя функция используется только для объединения промежуточных результатов (например, если выполняется параллельно).
Слишком сложно? Мы можем разделить этапы извлечения интересных свойств и их накопления:
Map.Entry<Integer, Integer> res = l.stream()
.map(x -> Map.entry(x.getInCount(), x.getOutCount()))
.reduce((x, y) -> Map.entry(x.getKey() + y.getKey(), x.getValue() + y.getValue()))
.orElseGet(() -> Map.entry(0, 0));