sun - tutorial stream java 8




Agrupamento do Java 8 usando o coletor customizado? (2)

Eu tenho a seguinte aula.

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;
    }
}

Eu gostaria de poder agrupar por idade e, em seguida, coletar a lista de nomes de pessoas em vez do próprio objeto Person; tudo em uma única expressão legal de lamba.

Para simplificar tudo isso, estou vinculando minha solução atual que armazena o resultado do agrupamento por idade e, em seguida, itera sobre ele para coletar os nomes.

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

members.add(new OtherPerson("Fred", IsoChronology.INSTANCE.date(1980, 6, 20), OtherPerson.Sex.MALE, "[email protected]"));
members.add(new OtherPerson("Jane", IsoChronology.INSTANCE.date(1990, 7, 15), OtherPerson.Sex.FEMALE, "[email protected]"));
members.add(new OtherPerson("Mark", IsoChronology.INSTANCE.date(1990, 7, 15), OtherPerson.Sex.MALE, "[email protected]"));
members.add(new OtherPerson("George", IsoChronology.INSTANCE.date(1991, 8, 13), OtherPerson.Sex.MALE, "[email protected]"));
members.add(new OtherPerson("Bob", IsoChronology.INSTANCE.date(2000, 9, 12), OtherPerson.Sex.MALE, "[email protected]"));

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

Solução atual

Não é ideal e, por uma questão de aprendizado, gostaria de ter uma solução mais elegante e eficiente.


Ao agrupar um Stream com Collectors.groupingBy , você pode especificar uma operação de redução nos valores com um Collector customizado. Aqui, precisamos usar Collectors.mapping , que usa uma função (o que é o mapeamento) e um coletor (como coletar os valores mapeados). Nesse caso, o mapeamento é Person::getName , ou seja, uma referência de método que retorna o nome da Pessoa e coletamos isso em uma List .

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

Você pode usar um Collector mapping para mapear a lista de Person para uma lista de nomes de pessoas:

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






collectors