java lambda java-8 java-stream collectors

¿Agrupación de Java 8 con un recopilador personalizado?



lambda java-8 (3)

Tengo la siguiente clase.

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

Me gustaría poder agrupar por edad y luego recopilar la lista de nombres de personas en lugar del objeto Persona en sí; todo en una sola expresión agradable de lamba.

Para simplificar todo esto, estoy vinculando mi solución actual que almacena el resultado de la agrupación por edad y luego lo repite para recopilar los nombres.

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

Solución actual

No es ideal y, en aras del aprendizaje, me gustaría tener una solución más elegante y eficiente.


Al agrupar una secuencia con Collectors.groupingBy , puede especificar una operación de reducción en los valores con un Collector personalizado. Aquí, necesitamos usar Collectors.mapping , que toma una función (qué es el mapeo) y un colector (cómo recolectar los valores mapeados). En este caso, la asignación es Person::getName , es decir, una referencia de método que devuelve el nombre de la Persona, y la recopilamos en una List .

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


Puede usar un Collector mapping para asignar la lista de Person a una lista de nombres de personas:

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


También puede usar Collectors.toMap y proporcionar una asignación para la función de clave, valor y combinación (si corresponde).

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