Search code examples
javajava-streamdowncast

Downcasting from superclass to several subclasses using Stream


That's my first post and it will be a tough one.

We have a list of Employee class elements, which at the same time can be elements of a 5 types of subclasses: ApprenticeEmployee, SalariedEmployee, CommissionEmployee, CommissionEmployeeWithSalary and HourlyEmployee, all of them contained in the same list employee.

ApprenticeEmployee: doesn't implement calculateSalary()

SalariedEmployee, CommissionEmployee, CommissionEmployeeWithSalary and hourlyEWmployee: implement calculateSalary().

The problem requires calculating the average salary using Stream. I've tried to do it using filter and mapingToDouble. The problem is the downcasting since we are not allowed to use conditionals (if-else) cos it said we are using "declarative language" and conditionals are against its philosophy. How could I downcast the elements depending on their subclass? I've tried with getClass(); but the returned class it's always Employee, not the subclass. The code i've tried it's:

public Double averageSalary() {
    return  employees.stream()
            .filter(employee -> !(employee instanceof ApprenticeEmployee))
            .mapToDouble(employee -> { 
                (employee.getClass()).cast(employee);
                return employee.calculateSalary();
            })
            .average()
            .getAsDouble();
}

calculateSalary() is a method from the interface Payroll, which is implemented by 4 out of the 5 subclasses, all of them but ApprenticeEmployee.

Sorry if I'm not typing the code in the proper way, I'm new to it! Thanks in advance!


Solution

  • I'd suggest to add an interface, where "calculateSalary" method will be allocated. Let us name it "CanCalculateSalary" for example. This interface will be implemented by all Employee classes which needs to be able to calculate salary. So your code would look like this:

     return employees.stream()
            .filter(CanCalculateSalary.class::isInstance)
            .mapToDouble(employee -> ((CanCalculateSalary)employee).calculateSalary())
            .average()
            .getAsDouble();