Java Collectors, группирующиеся по динамическим полям - PullRequest
3 голосов
/ 12 апреля 2019

У меня есть следующий вложенный блок groupingBy:

Map<String,Map<String,Long>> namesCountersMap =
            events.stream().collect(
                Collectors.groupingBy(
                    namesDAO::getName,
                    Collectors.groupingBy(
                        genericDAO::SOME_DYNAMIC_FIELD,
                        Collectors.counting())
                )
            );

Есть ситуация, когда мне нужно вызвать этот блок 3 раза, и единственное, что я изменяю, это внутреннее поле groupingBy ("SOME_DYNAMIC_FIELD").

В основном я пытаюсь использовать группирование и подсчет для каждого поля (на втором уровне) каждый раз, а затем объединять результаты.

Пример:

{
      "NamesRecords": {
        "Sam": {
            "Cars": 4
            "Bags": 6 
            "Houses": 2 
        },

        "Bob": {
            "Cars": 2
            "Bags": 1 
            "Houses": 3 
        },

      }
}

Как видите, группировка на 2-м уровне выполняется по 3 различным полям, поэтому мне нужно дублировать этот блок кода три раза.

Если я передам параметр fieldToGroupBy в функцию, можно ли использовать его динамически? Или, если у вас есть другие идеи о том, как избежать дублирования кода, я хотел бы услышать.

1 Ответ

3 голосов
/ 12 апреля 2019

Первый аргумент Collectors.groupingBy - это Function<T,R>, поэтому вы можете использовать переменную этого типа.

Это просто функциональный интерфейс с методом извлечения значения для группировки, и он может быть реализован с помощью ссылки на метод, лямбда-выражения, анонимного класса или любого другого типа класса.

Function<namesDAO, String> classifier2 = genericDAO::SOME_DYNAMIC_FIELD;

Map<String,Map<String,Long>> namesCountersMap =
        events.stream().collect(
            Collectors.groupingBy(
                namesDAO::getName,
                Collectors.groupingBy(
                    classifier2,
                    Collectors.counting())
            )
        );

Теперь вы можете назначать различные значения для classifier2, например

Function<namesDAO, String> classifier2 = someDAO::getCars;

Function<namesDAO, String> classifier2 = otherDAO::getBags;

Function<namesDAO, String> classifier2 = dao -> dao.getHouses();
...