获得 Java 流 api 的平均工资;
get average salary with Java stream api;
如何获取工资超过salaryLimit的公司员工的平均工资?
我想首先我需要获得所有薪水的列表并对其进行过滤+使用 mapToInt 和平均值,但是......没有任何效果((
public class TestCl {
@Data
@AllArgsConstructor
public class Company {
private List<Department> departments;
}
@Data
@AllArgsConstructor
public class Department {
private List<Employee> employees;
}
@Data
@AllArgsConstructor
public class Employee {
private int salary;
}
@Test
public void test() {
int salaryLimit = 25;
List<Employee> employees = new ArrayList<>(){{
add(new Employee(10));
add(new Employee(20));
add(new Employee(30));
add(new Employee(40));
add(new Employee(50));
}};
List<Department> departments = new ArrayList<>(){{
add(new Department(employees));
add(new Department(employees));
add(new Department(employees));
add(new Department(employees));
add(new Department(employees));
}};
Company company = new Company(departments);
float average = company.getDepartments().stream()
.map(Department::getEmployees).toList().stream()
.map(Employee::getSalary).toList().stream()
.filter(x -> x >= salaryLimit).mapToInt().average();
System.out.println(average);
}
}
一方面,您正在寻找 Stream.flatMap()
。例如,
company.getDepartments().stream()
.flatMap(d -> d.getEmployees().stream()) // ...
这会将您的 Departments
流转换为每个部门的 Employees
流。然后,您可以 map()
将这些添加到薪水并像您已经做的那样进行过滤。
组合 .toList().stream()
毫无意义,但是,因为它将一个流转换为另一个提供完全相同对象的流。删除它只有好处。
要映射到 IntStream
或者,可能更好地映射到 DoubleStream
,mapToInt()
或 mapToDouble()
方法需要一个函数来表达映射,您忽略了它。
最后,IntStream.average()
、DoubleStream.average()
、等 return一个OptionalInteger
/ OptionalDouble
/ etc,它适应了由于流提供零元素而没有平均值的可能性。你需要处理它。
全部加起来,那么:
float average = company.getDepartments().stream() // a stream of Departments
.flatMap(d -> d.getEmployees().stream()) // a stream of Employees
.map(e -> e.getSalary()) // a stream of Integer salaries
.filter(s -> s.intValue() >= salaryLimit) // only the high salaries
.mapToDouble(Integer::doubleValue) // as a DoubleStream
.average() // reduce to an average
.getAsDouble(); // the value, if it exists
请注意,如果没有薪水满足过滤条件,getAsDouble()
将抛出 NoSuchElementException
。捕获和处理是处理这种情况的一种完全合理的方法,但是如果你想避免这种情况,那么你可以存储 average()
的结果而不是链接 getAsDouble()
,然后用 [= 测试它29=] 来决定是继续 getAsDouble()
还是以不同的方式处理这种情况。或者,如果您想在这种情况下提供一个特定的 double
值——例如 0
或 Double.NaN
——那么您可以链接 orElse(valueForZeroSalaries)
而不是getAsDouble()
.
您得到的是编译器错误,因为 mapToInt
需要 ToIntFunction
但您提供的是 none.
此外,您不需要将流收集到列表中,只是为了再次将其转换为流。只要您不调用终端方法,您仍然可以使用您的流。
所以你可以做的是这样的:
double average = company.getDepartments().stream()
.flatMap(department -> department.getEmployees().stream())
.map(Employee::getSalary)
.filter(x -> x >= salaryLimit)
.mapToDouble(salary -> salary)
.average()
.orElse(0.0);
average()
给你一个 Optional<Double>
所以你需要在最后解包值。作为默认值,您可以 return 0.0
调用 orElse
如何获取工资超过salaryLimit的公司员工的平均工资? 我想首先我需要获得所有薪水的列表并对其进行过滤+使用 mapToInt 和平均值,但是......没有任何效果((
public class TestCl {
@Data
@AllArgsConstructor
public class Company {
private List<Department> departments;
}
@Data
@AllArgsConstructor
public class Department {
private List<Employee> employees;
}
@Data
@AllArgsConstructor
public class Employee {
private int salary;
}
@Test
public void test() {
int salaryLimit = 25;
List<Employee> employees = new ArrayList<>(){{
add(new Employee(10));
add(new Employee(20));
add(new Employee(30));
add(new Employee(40));
add(new Employee(50));
}};
List<Department> departments = new ArrayList<>(){{
add(new Department(employees));
add(new Department(employees));
add(new Department(employees));
add(new Department(employees));
add(new Department(employees));
}};
Company company = new Company(departments);
float average = company.getDepartments().stream()
.map(Department::getEmployees).toList().stream()
.map(Employee::getSalary).toList().stream()
.filter(x -> x >= salaryLimit).mapToInt().average();
System.out.println(average);
}
}
一方面,您正在寻找 Stream.flatMap()
。例如,
company.getDepartments().stream()
.flatMap(d -> d.getEmployees().stream()) // ...
这会将您的 Departments
流转换为每个部门的 Employees
流。然后,您可以 map()
将这些添加到薪水并像您已经做的那样进行过滤。
组合 .toList().stream()
毫无意义,但是,因为它将一个流转换为另一个提供完全相同对象的流。删除它只有好处。
要映射到 IntStream
或者,可能更好地映射到 DoubleStream
,mapToInt()
或 mapToDouble()
方法需要一个函数来表达映射,您忽略了它。
最后,IntStream.average()
、DoubleStream.average()
、等 return一个OptionalInteger
/ OptionalDouble
/ etc,它适应了由于流提供零元素而没有平均值的可能性。你需要处理它。
全部加起来,那么:
float average = company.getDepartments().stream() // a stream of Departments
.flatMap(d -> d.getEmployees().stream()) // a stream of Employees
.map(e -> e.getSalary()) // a stream of Integer salaries
.filter(s -> s.intValue() >= salaryLimit) // only the high salaries
.mapToDouble(Integer::doubleValue) // as a DoubleStream
.average() // reduce to an average
.getAsDouble(); // the value, if it exists
请注意,如果没有薪水满足过滤条件,getAsDouble()
将抛出 NoSuchElementException
。捕获和处理是处理这种情况的一种完全合理的方法,但是如果你想避免这种情况,那么你可以存储 average()
的结果而不是链接 getAsDouble()
,然后用 [= 测试它29=] 来决定是继续 getAsDouble()
还是以不同的方式处理这种情况。或者,如果您想在这种情况下提供一个特定的 double
值——例如 0
或 Double.NaN
——那么您可以链接 orElse(valueForZeroSalaries)
而不是getAsDouble()
.
您得到的是编译器错误,因为 mapToInt
需要 ToIntFunction
但您提供的是 none.
此外,您不需要将流收集到列表中,只是为了再次将其转换为流。只要您不调用终端方法,您仍然可以使用您的流。
所以你可以做的是这样的:
double average = company.getDepartments().stream()
.flatMap(department -> department.getEmployees().stream())
.map(Employee::getSalary)
.filter(x -> x >= salaryLimit)
.mapToDouble(salary -> salary)
.average()
.orElse(0.0);
average()
给你一个 Optional<Double>
所以你需要在最后解包值。作为默认值,您可以 return 0.0
调用 orElse