I have the following nested groupingBy block:
Map<String,Map<String,Long>> namesCountersMap =
events.stream().collect(
Collectors.groupingBy(
namesDAO::getName,
Collectors.groupingBy(
genericDAO::SOME_DYNAMIC_FIELD,
Collectors.counting())
)
);
There is a situation where I need to call this block 3 times, and the only thing I change is the inner groupingBy field ("SOME_DYNAMIC_FIELD").
Basically what i'm trying to do, is to use group-by and counting for a different field (at the second level) every time, and then merge the results.
Example:
{
"NamesRecords": {
"Sam": {
"Cars": 4
"Bags": 6
"Houses": 2
},
"Bob": {
"Cars": 2
"Bags": 1
"Houses": 3
},
}
}
As you can see, group-by at the 2nd level is done by 3 different fields, that's is why I need to duplicate this block of code three times.
If I pass a parameter of fieldToGroupBy to the function, is there a way I can use it dynamically? Or if you have any other ideas of how to avoid code duplication, I would love to hear.
The first argument to Collectors.groupingBy
is a Function<T,R>
, so you can use a variable of that type.
It is simply a functional interface with a method for extracting the value to group by, and it can be implemented by a method reference, a lambda expression, an anonymous class, or any other type of class.
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())
)
);
Now you can assign different values to classifier2
, e.g.
Function<namesDAO, String> classifier2 = someDAO::getCars;
Function<namesDAO, String> classifier2 = otherDAO::getBags;
Function<namesDAO, String> classifier2 = dao -> dao.getHouses();