Often there is the need to transform results for a query like:
select category, count(*)
from table
group by category
to a map in which keys are categories and values are count of records belonging to the same category.
Many persistence frameworks return the results of such a query as List<Object[]>
, where object arrays contain two elements (category and the count for each returned result set row).
I am trying to find the most readable way to convert this list to the corresponding map.
Of course, traditional approach would involve creating the map and putting the entries manually:
Map<String, Integer> map = new HashMap<>();
list.stream().forEach(e -> map.put((String) e[0], (Integer) e[1]));
The first one-liner that came to my mind was to utilize the out of the box available Collectors.toMap
collector:
Map<String, Integer> map = list.stream().collect(toMap(e -> (String) e[0], e -> (Integer) e[1]));
However, I find this e -> (T) e[i]
syntax a bit less readable than traditional approach. To overcome this, I could create a util method which I can reuse in all such situations:
public static <K, V> Collector<Object[], ?, Map<K, V>> toMap() {
return Collectors.toMap(e -> (K) e[0], e -> (V) e[1]);
}
Then I've got a perfect one-liner:
Map<String, Integer> map = list.stream().collect(Utils.toMap());
There is even no need to cast key and value because of type inference. However, this is a bit more difficult to grasp for other readers of the code (Collector<Object[], ?, Map<K, V>>
in the util method signature, etc).
I am wondering, is there anything else in the java 8 toolbox that could help this to be achieved in a more readable/elegant way?