Error simplifying methods and ordering by Id in Java8 - Collectors

Viewed 51

I have the following methods almost the same and very similar:

public static Map<String, Long> countTotalCities(List<OrderData> orderDataList) {
    return orderDataList.stream()
            .collect(Collectors.groupingBy(
                    OrderData::getCity,
                    Collectors.counting()));
}

public static Map<String, Long> countTotalType(List<OrderData> orderDataList) {
    return orderDataList.stream()
            .collect(Collectors.groupingBy(
                    OrderData::getType,
                    Collectors.counting()));
}

public static Map<String, Long> countTotalChannels(List<OrderData> orderDataList) {
    return orderDataList.stream()
            .collect(Collectors.groupingBy(
                    OrderData::getChannel,
                    Collectors.counting()));
}

The getCity, getType, and getChannel methods are of type String. Is there a way to put these 3 methods in 1 method and pass a String parameter to the method for simplicity. I want to have 1 single method instead of 3. I've even thought that I could have the same map for all results. I want to do something like this:

public static Map<String, Long> countTotalResults(List<OrderData> orderDataList, String field) {
    return orderDataList.stream()
            .collect(Collectors.groupingBy(field,Collectors.counting()));
}

But I get the following compilation error when I try to do this: Collectors.groupingBy(field,...)

This is the error shown: reason: no instance(s) of type variable(s) K, T exist so that String conforms to Function

I also want to sort these results into an OrderId. I don't know how to indicate this order in Java 8.

2 Answers

The groupingBy() accepts as first argument a Function that maps an OrderData as a String (regarding your Map here) so that's the type of parameter you need to have in the signature :

... countTotalResults(List<OrderData> orderDataList, Function<OrderData, String> classifier) 

Then to call it, give it the function:

  • as method reference

    countTotalResults(someList, OrderData::getChannel);
    
  • as lambda

    countTotalResults(null, o -> o.getChannel());
    

The whole method including the sorting part

public static Map<String, Long> countTotalResults(List<OrderData> orderDataList, Function<OrderData, String> classifier) {
    return orderDataList.stream().sorted(Comparator.comparingLong(OrderData::getOrderId))
                                 .collect(groupingBy(classifier, counting()));
}

The method can take just a Function<OrderData, String>:

public static Map<String, Long> countTotalResults(List<OrderData> orderDataList, 
         Function<OrderData, String> mapper) {
    return orderDataList.stream()
            .sorted(Comparator.comparingLong(OrderData::getOrderId))
            .collect(Collectors.groupingBy(mapper,Collectors.counting()));
}

Which will allow you to call with the same method references:

countTotalResults(list, OrderData::getCity);
countTotalResults(list, OrderData::getType);
countTotalResults(list, OrderData::getChannel);
Related