Search code examples
javajava-8java-streamcollectors

Custom Collector Implementation for summing float java 8


I am trying to create a custom float addition similar to Collectors.summingDouble().

But I am facing 2 issues and I am not sure about how to fix it.

  1. BiConsumer - Line #27 - void methods cannot return a value
  2. Collectors.of - Line#32 - The method of(Supplier, BiConsumer<R,T>, BinaryOperator<R>, Collector.Characteristics...) in the type Collector is not applicable for the arguments (Supplier<Float[]>, BiConsumer<Float,Employee>, BinaryOperator<Float>) What needs to be done here for fixing the issue?
public class CustomCollector {


    public static void main(String[] args) {
        Employee e1=new Employee(1,"Tom",10.2f);
        Employee e2=new Employee(1,"Jack",10.4f);
        Employee e3=new Employee(1,"Harry",10.4f);
        ArrayList<Employee> lstEmployee=new ArrayList<Employee>();
        lstEmployee.add(e1);lstEmployee.add(e2);lstEmployee.add(e3);

/*  Implementation 1
 *  double totalSal=lstEmployee.stream().collect(Collectors.summingDouble(e->e.getSal()));
        System.out.println(totalSal);
*/  
        //Implementation 2
        Function<Employee,Float> fun=(e)->e.getSal();
        BiConsumer<Float,Employee> consumer=(val,e)->val+e.getSal();
        BinaryOperator<Float> operator=(val1,val2)->val1+val2;
        Supplier<Float[]> supplier=() -> new Float[2];

        float FtotalSal=lstEmployee.stream().collect(
                Collector.of(supplier,consumer,operator));
        System.out.println(FtotalSal);
    }

}

class Employee {
    int id;
    String name;
    float sal;
    // getters, setter, constructror
}

Solution

  • It seems, you are confusing Reduction with Mutable Reduction.

    Your functions, (val, e) -> val + e.getSal() and (val1, val2) -> val1 + val2), are suitable for a Reduction operation, but not for collect. The supplier, producing a Float[] array of length two, doesn’t fit to it at all.

    E.g., you can perform your operation using

    float f = lstEmployee.stream().reduce(
        0F,
        (val, e) -> val + e.getSal(),
        (val1, val2) -> val1 + val2);
    

    This bears some boxing overhead, as all intermediate sums are represented as Float objects.

    You can avoid this using Mutable Reduction, when you create a mutable container which is capable of holding a float value without boxing, i.e. new float[1]. Then, you have to supply functions accepting an array argument and changing the contained value. Since your intended result is a float, rather than an array, you further need a finisher to produce the final result.

    float f = lstEmployee.stream().collect(
        Collector.of(
            () -> new float[1], // a container capable of holding one float
            (floatArray,e) -> floatArray[0] += e.getSal(), // add one element to the array
            (a1, a2) -> { a1[0] += a2[0]; return a1; }, // merge two arrays
            array -> array[0]) // extracting the final result value
        );
    

    Of course, this is only for exercising, as you have already shown to know a simpler solution using builtin features.