gpa
gpa

Reputation: 2451

Streams Collectors.summingDouble dynamic function argument

I have following code which works great if i hard-code pojo method Employee::getBaseSalary

Map<Date, Map<String, Double>> $r = list
                                .stream()
                                .filter((p) -> (StringUtils.equalsIgnoreCase(p.getActiveInd(), "Y")
                                                && CoreUtils.greaterThanOrEquals(p.getCreateDate(), paramDate) && (null == p.getEmpDate())))
                                .collect(Collectors.groupingBy(dateFn,
                                         Collectors.groupingBy(empCodeFn,
                                         Collectors.summingDouble(Employee::getBaseSalary))));

Question

Notice that i have java Function Objects used dateFn and empCodeFn in group by clause. I am trying to do the same for summingDouble as follows but it give compile errors??

    private Function<Employee, Double> getFunctionSpecialCalc() {
    switch (calculationType) {
        case BaseSalary:
            return Employee::getBaseSalary;
        case TotalSalary:
            return Employee::getTotalSalary;
        default:
            return Employee::getBaseSalary;
    }
}

And i am intended to use it as follows:

Function<Employee,Double> calcFn = getFunctionSpecialCalc();
...
...    
Collectors.summingDouble(calcFn))));

Compile Error The method summingDouble(ToDoubleFunction) in the type Collectors is not applicable for the arguments (Function)

I understand that it needs now function type as ToDoubleFunction, but now issue is how to inject dynamically function into SummingDouble?

Solution After investigation, i have found following solution. Its not that great and clean as using Function Object. Please update if you have better solution to the problem.

        Collectors.summingDouble((o)->{if(Type.BaseSalary.equals(calculationType)) 
      return o.getBaseSalary();
 else return o.getTotalSalary();
}))));

Upvotes: 0

Views: 1705

Answers (1)

Eugene
Eugene

Reputation: 120858

I don't think you should do that step in the collect part; instead it should be part of some map one. But since this is part of a Collector I would go with a Collectors.mapping, like so:

Map<Date, Map<String, Double>> $r = list
       .stream()
       .filter((p) -> (StringUtils.equalsIgnoreCase(p.getActiveInd(), "Y")
                                            && CoreUtils.greaterThanOrEquals(p.getCreateDate(), paramDate) && (null == p.getEmpDate())))
       .collect(Collectors.groupingBy(dateFn,
             Collectors.groupingBy(empCodeFn,
             Collectors.mapping(o-> {
                   if(Type.BaseSalary.equals(calculationType)) 
                        return o.getBaseSalary();
                   else return o.getTotalSalary();
             }, Collectors.summingDouble(x -> x)
   ))));

Upvotes: 2

Related Questions