Reputation: 133
I have an ArrayList
of user-defined object employee as
class Employee {
String name;
Double age;
Double salary
}
I am trying to reduce the above list as a stream via the following code
Double totalSalary = empList.stream().parallel().filter(x-> x.getname().equalsIgnoreCase("XYZ")).reduce(0,(subTotal, sal)-> subTotal + dp.getSalary(), DoubleExpression::add);
This does not compile and gives an error. How can I achieve my desired objective?
Upvotes: 6
Views: 2036
Reputation: 31868
Ravindra's answer provides a correct solution, but to understand in detail why your solution doesn't work, consider these:
Double totalSalary = empList.stream().parallel()
.filter(x -> x.getName().equalsIgnoreCase("XYZ"))
// crucial aspect of mapping to the type that you want to reduce
.map(Employee::getSalary)
// reduction as a stage of stream pipeline execution
.reduce(0, // identity element for sum, but with a flaw!!
(subTotal, sal) -> Double.sum(subTotal, sal), // accumulator to sum double values
Double::sum // the combiner function compatible with accumulation
);
The reason why the identity is flawed is that, because of 0, the type of subTotal
in the accumulator would not be inferred as double
as expected by the Double#sum
method. Hence updating the code further to using Double.NaN
would make it work as :
Double totalSalary = empList.stream().parallel()
.filter(x -> x.getName().equalsIgnoreCase("XYZ"))
.map(Employee::getSalary)
.reduce(Double.NaN, Double::sum, Double::sum); // identity element and method reference for accumulator
Though note, this could be simply represented with the exclusion of the combiner in this case as:
Double totalSalary = empList.stream().parallel()
.filter(x -> x.getName().equalsIgnoreCase("XYZ"))
.map(Employee::getSalary)
.reduce(Double.NaN, Double::sum);
and since sum
eventually is an operation of primitive types, it would be much convenient to use the DoubleStream
mapping which is a primitive specialization of the stream for double-valued elements.
Upvotes: 2
Reputation: 21124
First you have to map
the Employee object into a double salary. Then only you can do the reduction step. Moreover, the reduction step takes an identity element and a binary operator. But you have passed three arguments there, which is flawed too.
double totalSalary = empList.stream()
.filter(x -> x.getName().equalsIgnoreCase("XYZ"))
.mapToDouble(Employee::getSalary)
.sum();
Here's the equivalent reduction. Notice that 0 is the identity element for this reduction.
double totalSalary = empList.stream()
.filter(x -> x.getName().equalsIgnoreCase("XYZ"))
.mapToDouble(Employee::getSalary)
.reduce(0, Double::sum);
Upvotes: 11