Joey Yi Zhao
Joey Yi Zhao

Reputation: 42444

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?

Upvotes: 1

Views: 543

Answers (1)

pscuderi
pscuderi

Reputation: 1554

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()));

Upvotes: 1

Related Questions