Я заблокирован при использовании Функциональное программирование Java для Построение карты .В моем случае использования, это только пример, я хотел бы построить Map<Integer, Map<Integer, List<Person>>>
, начиная с List<Person>
.
. Первый шаг очень прост: я создаю первый Map<Integer, List<person>>
.
.
Затем я хочу добавить новый уровень группировки , чтобы он создал новую карту: Map<Integer, Map<Integer, List<person>>>
.
Суть в том, как правильно использовать все возможности Collectors (groupingBy,отображение, может что-то еще) добавить новый уровень группировки?Все мои попытки не увенчались успехом: компилятор всегда говорит мне, что все предоставленные мной функции не соответствуют ожидаемым.
Вкратце приведем код:
Сначала класс Person, а затем метод длябыстро составить список:
public class Person {
private long id;
private String firstName;
private String lastName;
private Date birthDate;
private int alea;
...
Этот метод (расположенный в классе DataBuilder) просто создает список Person для предоставления данных в основной класс:
public List<Person> getPersons() {
List<Person> persons = new ArrayList<>();
Supplier<Person> person = Person::new;
for (int cpt = 0; cpt < 10; cpt++) {
Person p = person.get();
p.setId(cpt);
p.setFirstName("fn" + cpt);
p.setLastName("ln" + cpt);
p.setBirthDate(new Date(119, cpt, 10 + cpt));
p.setAlea(cpt % 2);
persons.add(p);
}
return persons;
}
в основном,Построение первого уровня карты не является проблемой:
public static void main(String[] args) {
DataBuilder db = new DataBuilder();
List<Person> persons = db.getPersons();
Map<Integer, List<Person>> mapAleaPerson = persons.stream()
.collect(Collectors.groupingBy(Person::getAlea,
Collectors.mapping(p -> p, Collectors.toList())));
mapAleaPerson.forEach((k,v) -> System.out.printf("%n%s contains %s%n", k, v));
Результат в консоли в порядке:
0 contains [Person [id=0, firstName=fn0, lastName=ln0, alea=0], Person [id=2, firstName=fn2, lastName=ln2, alea=0], Person [id=4, firstName=fn4, lastName=ln4, alea=0], Person [id=6, firstName=fn6, lastName=ln6, alea=0], Person [id=8, firstName=fn8, lastName=ln8, alea=0]]
1 contains [Person [id=1, firstName=fn1, lastName=ln1, alea=1], Person [id=3, firstName=fn3, lastName=ln3, alea=1], Person [id=5, firstName=fn5, lastName=ln5, alea=1], Person [id=7, firstName=fn7, lastName=ln7, alea=1], Person [id=9, firstName=fn9, lastName=ln9, alea=1]]
Теперь я хотел бы добавить новый уровень группировки.Я выбрал год рождения, это другое свойство объекта Person.
По сути, я пытался что-то вроде этого:
Map<Integer,Map<Integer,List<Person>>> mapByYearThenAleaPerson = persons.stream()
.collect(Collectors.groupingBy(p -> p.getBirthDate().getYear(),
Collectors.toMap(Collectors.groupingBy(Person::getAlea,
Collectors.mapping(p -> p, Collectors.toList())))));
Приведение не помогает:
@SuppressWarnings("unchecked")
Map<Integer,Map<Integer,List<Person>>> mapByYearThenAleaPerson = persons.stream()
.collect(Collectors.groupingBy(p -> p.getBirthDate().getYear(),
Collectors.toMap((Function<Integer, List<Person>>) Collectors.groupingBy(Person::getAlea,
Collectors.mapping(p -> p, Collectors.toList())))));
Я также пытался использовать Collectors.mapping вместо Collectors.toMap:
Map<Integer,Map<Integer,List<Person>>> mapByYearThenAleaPerson = persons.stream()
.collect(Collectors.groupingBy(p -> p.getBirthDate().getYear(),
Collectors.mapping((Function<Integer, List<Person>>) Collectors.groupingBy(Person::getAlea,
Collectors.mapping(p -> p, Collectors.toList())))));
Каждый раз, когда компилятор возвращает ошибку из-за несовместимого типа функции.
Единственный способ, которым ядобавлено, что новый уровень группировки был добавлен с помощью старого кода Java и добавления внешнего цикла и группировки данных в Map of Map.
Нецелесообразно встраивать FP в старую Java !!
Есть кто-нибудьИдея сделать все это с чистым FP?
После ответа @eran (это прекрасно работает) вот что я сделал и его результат:
Map<Integer, Map<Integer, List<Person>>> mapByYearThenAleaPerson = persons.stream().collect(
Collectors.groupingBy(p -> p.getBirthDate().getYear() + 1900, Collectors.groupingBy(Person::getAlea)));
{2018={0=[Person [id=0, firstName=fn0, lastName=ln0, alea=0], Person [id=2, firstName=fn2, lastName=ln2, alea=0], Person [id=4, firstName=fn4, lastName=ln4, alea=0]], 1=[Person [id=1, firstName=fn1, lastName=ln1, alea=1], Person [id=3, firstName=fn3, lastName=ln3, alea=1]]}, 2019={0=[Person [id=6, firstName=fn6, lastName=ln6, alea=0], Person [id=8, firstName=fn8, lastName=ln8, alea=0]], 1=[Person [id=5, firstName=fn5, lastName=ln5, alea=1], Person [id=7, firstName=fn7, lastName=ln7, alea=1], Person [id=9, firstName=fn9, lastName=ln9, alea=1]]}}
Что такоедействительно удивительно, простота вложенного оператора groupingBy
по сравнению со способом построения самой первой карты.
Почему нам больше не нужно указывать mapping
и Collectors.toList()
?