Для этого очень упрощенного примера моей проблемы у меня есть объект Stat
с полем year
и три других поля статистики. Представьте, что это результаты ежегодной статистики по количеству пациентов каждого типа животных из ветвей ветеринарной сети, и я хочу получить суммы по всем ветвям по годам.
Другими словами, из списка Stat
объектов я бы хотел вернуть Map<Integer, Stat>
, где целое число - это год, а объект Stat имеет год и суммы для каждого из четырех полей.
public class Stat
{
int year;
public int getYear() { return year; }
long cats;
public long getCats() { return cats; }
long dogs;
public long getDogs() { return dogs; }
long pigeons;
public long getPigeons() { return pigeons; }
public Stat(int year, long cats, long dogs, long pigeons)
{
this.year = year;
this.cats = cats;
this.dogs = dogs;
this.pigeons = pigeons;
}
public Stat(Stat left, Stat right)
{
if (left.year != right.year)
throw new IllegalArgumentException("Only allow combining for same year.");
this.year = left.year;
this.cats = left.cats + right.cats;
this.dogs = left.dogs + right.dogs ;
this.pigeons = left.pigeons + right.pigeons;
}
@Override
public String toString()
{
return String.format("%d c=%d d=%d p=%d", year, cats, dogs, pigeons);
}
}
@Test
public void testStat()
{
List<Stat> items = Arrays.asList(
new Stat(2017, 5, 8, 12),
new Stat(2017, 123, 382, 15),
new Stat(2018, 1, 2, 3)
);
Map<Integer, Optional<Stat>> result = items.stream()
.collect(Collectors.groupingBy(Stat::getYear,
Collectors.reducing(Stat::new)
));
System.out.println(result);
}
Optional
не является необходимым, поскольку groupingBy
никогда не создаст List
, который нуждается в reducing
, если бы не было элементов.
Есть ли способ получить Map<Integer, Stat>
, желательно без необходимости создания пустого объекта "личность"?
Если мне нужно прибегнуть к созданию функции создания идентификатора для reducing
, то у конструктора объединения объекта Stat должен быть год (см. Конструктор), так как же конструктору идентификаторов можно передать ему год?