Java 8 grouping using custom collector?

女生的网名这么多〃 提交于 2019-11-26 11:30:11

问题


I have the following class.

class Person {

    String name;
    LocalDate birthday;
    Sex gender;
    String emailAddress;

    public int getAge() {
        return birthday.until(IsoChronology.INSTANCE.dateNow()).getYears();
    }

    public String getName() {
        return name;
    }
}

I\'d like to be able to group by age and then collect the list of the persons names rather than the Person object itself; all in a single nice lamba expression.

To simplify all of this I am linking my current solution that store the result of the grouping by age and then iterates over it to collect the names.

ArrayList<OtherPerson> members = new ArrayList<>();

members.add(new OtherPerson(\"Fred\", IsoChronology.INSTANCE.date(1980, 6, 20), OtherPerson.Sex.MALE, \"fred@example.com\"));
members.add(new OtherPerson(\"Jane\", IsoChronology.INSTANCE.date(1990, 7, 15), OtherPerson.Sex.FEMALE, \"jane@example.com\"));
members.add(new OtherPerson(\"Mark\", IsoChronology.INSTANCE.date(1990, 7, 15), OtherPerson.Sex.MALE, \"mark@example.com\"));
members.add(new OtherPerson(\"George\", IsoChronology.INSTANCE.date(1991, 8, 13), OtherPerson.Sex.MALE, \"george@example.com\"));
members.add(new OtherPerson(\"Bob\", IsoChronology.INSTANCE.date(2000, 9, 12), OtherPerson.Sex.MALE, \"bob@example.com\"));

Map<Integer, List<Person>> collect = members.stream().collect(groupingBy(Person::getAge));

Map<Integer, List<String>> result = new HashMap<>();

collect.keySet().forEach(key -> {
            result.put(key, collect.get(key).stream().map(Person::getName).collect(toList()));
});

Current solution

Not ideal and for the sake of learning I\'d like to have a more elegant and performing solution.


回答1:


When grouping a Stream with Collectors.groupingBy, you can specify a reduction operation on the values with a custom Collector. Here, we need to use Collectors.mapping, which takes a function (what the mapping is) and a collector (how to collect the mapped values). In this case the mapping is Person::getName, i.e. a method reference that returns the name of the Person, and we collect that into a List.

Map<Integer, List<String>> collect = 
    members.stream()
           .collect(Collectors.groupingBy(
               Person::getAge,
               Collectors.mapping(Person::getName, Collectors.toList()))
           );



回答2:


You can also use Collectors.toMap and provide mapping for key, value and merge function(if any).

Map<Integer, String> ageNameMap = 
    members.stream()
            .collect(Collectors.toMap(
              person -> person.getAge(), 
              person -> person.getName(), (pName1, pName2) -> pName1+"|"+pName2)
    );



回答3:


You can use a mapping Collector to map the list of Person to a list of person names :

Map<Integer, List<String>> collect = 
    members.stream()
           .collect(Collectors.groupingBy(Person::getAge,
                                          Collectors.mapping(Person::getName, Collectors.toList())));


来源:https://stackoverflow.com/questions/33345413/java-8-grouping-using-custom-collector

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!