Zhao Yi Zhao Yi - 1 month ago 9
Java Question

How to use java8 stream to calculate sum of values combined with a grouping by statement

I have a Person class which has gender and age fields. I want to get the sum of age for each gender by below code.

public void test() {
List<Person> roster = new ArrayList();

Map<Integer, Integer> totalAgeByGender =
roster
.stream()
.collect(
Collectors.groupingBy(
Person::getGender,
Collectors.reducing(
0,
Person::getAge,
Double::sum)));
}

static class Person {

private int gender;
private double age;

public int getGender() {
return gender;
}

public double getAge() {
return age;
}
}
}


I am having a compile error with above code as below:

Bad return type in method reference: cannot convert double to U.


It complains the last part of the steam statement
Double::sum
. If I change the type of age to integer and use
Integer::sum
in the above code, it works fine. I wander what wrong with the Double::sum in this case.

In addition, is it possible to group by the sex field and return
Map<Integer, List<Person>>
from one steam statement?

Answer

You've got the following 2 slight problems here: (1) your identify is being interpreted as an Integer; and (2) the values of your map are Double(s).

Map<Integer, Double> totalAgeByGender = // not Map<Integer, Integer>
    roster.stream()
        .collect(Collectors.groupingBy(
            Person::getGender,
            Collectors.reducing(
                0d, // not 0
                Person::getAge,
                Double::sum)));

As mentioned below, you could make this more concise and less error prone using Collectors.summingDouble:

Map<Integer, Double> totalAgeByGender = roster.stream()
    .collect(Collectors.groupingBy(
        Person::getGender,
        Collectors.summingDouble(Person::getAge)));

You can group by sex (gender) easily enough:

Map<Integer, List<Person>> sexToPeople = roster.stream()
    .collect(Collectors.groupingBy(
        Person::getGender, 
        Collectors.toList()));
Comments