Java 使用Stream从超类向下投射到几个子类
这是我的第一篇文章,这将是一篇艰难的文章 我们有一个Employee类元素列表,它同时可以是5类子类的元素:Java 使用Stream从超类向下投射到几个子类,java,java-stream,downcast,Java,Java Stream,Downcast,这是我的第一篇文章,这将是一篇艰难的文章 我们有一个Employee类元素列表,它同时可以是5类子类的元素:学徒员工,工薪员工,专员员工,专员员工带薪员工和小时员工,它们都包含在同一个员工列表中 学徒员工:未实施calculateSalary() 受薪员工,委员员工,委员员工,带薪员工和小时员工:实施计算工资() 这个问题需要使用Stream计算平均工资。我已经尝试使用filter和mapingToDouble来完成它。问题是我们不允许使用条件句(如果有的话),因为它说我们使用的是“声明性语言”
学徒员工
,工薪员工
,专员员工
,专员员工带薪员工
和小时员工
,它们都包含在同一个员工列表中
学徒员工:未实施calculateSalary()
受薪员工,委员员工,委员员工,带薪员工和小时员工:实施计算工资()
这个问题需要使用Stream计算平均工资。我已经尝试使用filter和mapingToDouble来完成它。问题是我们不允许使用条件句(如果有的话),因为它说我们使用的是“声明性语言”,而条件句违背了它的哲学。如何根据元素的子类向下转换元素?我已尝试使用getClass();但是返回的类总是Employee,而不是子类。我试过的代码是:
public Double averageSalary() {
return employees.stream()
.filter(employee -> !(employee instanceof ApprenticeEmployee))
.mapToDouble(employee -> {
(employee.getClass()).cast(employee);
return employee.calculateSalary();
})
.average()
.getAsDouble();
}
calculateSalary()
是来自接口Payroll
的一种方法,该方法由5个子类中的4个子类实现,除了之外,其他所有子类都是Payroll
对不起,如果我没有以正确的方式键入代码,我是新手!提前谢谢 我建议添加一个接口,其中将分配“calculateSalary”方法。例如,让我们将其命名为“CanCalculateSalary”。该接口将由需要能够计算工资的所有员工类实现。因此,您的代码如下所示:
return employees.stream()
.filter(CanCalculateSalary.class::isInstance)
.mapToDouble(employee -> ((CanCalculateSalary)employee).calculateSalary())
.average()
.getAsDouble();
我建议添加一个接口,其中将分配“calculateSalary”方法。例如,让我们将其命名为“CanCalculateSalary”。该接口将由需要能够计算工资的所有员工类实现。因此,您的代码如下所示:
return employees.stream()
.filter(CanCalculateSalary.class::isInstance)
.mapToDouble(employee -> ((CanCalculateSalary)employee).calculateSalary())
.average()
.getAsDouble();
有了关于声明方法的接口的信息,就很简单了
public Double averageSalary() {
return employees.stream()
.filter(employee -> employee instanceof Payroll)
.mapToDouble(employee -> ((Payroll) employee).calculateSalary())
.average()
.getAsDouble();
}
这还有更多的优点:它允许将来添加更多的Employee
子类,其中一些子类可能实现Payroll
,而有些子类可能不实现。您仍然不需要修改上面的代码(但是使用新的子类再次测试它)。使用有关接口的信息声明您的方法是简单的
public Double averageSalary() {
return employees.stream()
.filter(employee -> employee instanceof Payroll)
.mapToDouble(employee -> ((Payroll) employee).calculateSalary())
.average()
.getAsDouble();
}
这还有更多的优点:它允许将来添加更多的Employee
子类,其中一些子类可能实现Payroll
,而有些子类可能不实现。您仍然不需要修改上面的代码(但使用新的子类再次测试它)。其他类之间是否存在可派生的关系(除了和)?或者,您认为您应该如何将专员员工
反对对象转换为受薪员工
?它们结合在一起的唯一一件事是它们有一个共同的父对象……换句话说,employees
collection的类型是什么?是否有一个与方法calculateSalary()
的接口,该方法由您拥有的5个类中的4个实现?Class.cast()
不会更改给定参数的类型,因此变量employee
仍然是employee
对象。但是,cast()
方法将给定的参数作为所使用的类
对象的类型返回。但最终,这种方法在这种情况下对您没有用处。其他类(除了学徒员工
)之间是否存在可衍生的关系?或者,您认为您应该如何将专员员工
反对对象转换为受薪员工
?它们结合在一起的唯一一件事是它们有一个共同的父对象……换句话说,employees
collection的类型是什么?是否有一个与方法calculateSalary()
的接口,该方法由您拥有的5个类中的4个实现?Class.cast()
不会更改给定参数的类型,因此变量employee
仍然是employee
对象。但是,cast()
方法将给定的参数作为所使用的类
对象的类型返回。但最终,这种方法在这种情况下对您没有用处。我想您可能需要删除检查实例中的code>,因为您正在删除CanCalculateSalary
atm的实例。(.filter(CanCalculateSalary.class::isInstance)
是更惯用的方法。)@AndyTurner是的,谢谢。map(CanCalculateSalary::calculateSalary)
应该可以工作,而不是显式转换。如果没有,那么,map(CanCalculateSalary.class::cast).mapToDouble(CanCalculateSalary::calculateSalary)
应该可以帮助Sergey!非常感谢,它已经实施并正在运行。我错误地处理了这个问题:我是按子类过滤的,您清楚地告诉我应该按接口过滤。像这样简单。嘿,凯特尔,不客气:)我想你可能想删除检查实例中的code>,因为您正在删除CanCalculateSalary
atm的实例。(.filter(CanCalculateSalary.class::isInstance)
是更惯用的方法。)@AndyTurner是的,谢谢。map(CanCalculateSalary::calculateSalary)
应该可以工作,而不是显式转换。如果没有,那么,map(CanCalculateSalary.class::cast).mapToDouble(CanCalculateSalary::calculateSalary)
应该可以帮助Sergey!非常感谢,它已经实施并正在运行。我错误地处理了这个问题:我是按子类过滤的,您清楚地告诉我应该按接口过滤。像这样简单。嘿,凯特尔,不客气:)谢谢你!我应该把它贴上去