簡體   English   中英

用 Java stream 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的 stream 轉換為每個部門的Employees的 stream。 然后,您可以將它們map()到薪水並像您已經做的那樣進行過濾。

然而,組合.toList().stream()意義,因為它將一個 stream 轉換為另一個提供完全相同對象的工作。 刪除它只有好處。

要將 map 轉換為IntStream或者,為了這個目的可能更好,一個DoubleStreammapToInt()mapToDouble()方法需要一個 function 來表達映射的細節,你忽略了。

最后, IntStream.average()DoubleStream.average()返回一個OptionalInteger / OptionalDouble / etc ,它適應了由於 stream 提供零元素而沒有平均值的可能性。 你需要處理它。

一起,然后:

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() ,然后用isPresent()測試它以確定是否使用getAsDouble()提前到 go 或以不同方式處理這種情況。 或者,如果您想在這種情況下提供特定的double精度值——例如0Double.NaN那么您可以鏈接orElse(valueForZeroSalaries)而不是getAsDouble()

你得到的是一個編譯器錯誤,因為mapToInt需要一個ToIntFunction但你沒有提供。

此外,您不需要將 stream 收集到列表中,只是為了再次將其轉換為 stream。 只要不調用終端方法,您仍然可以使用 stream。

所以你可以做的是這樣的:

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>所以你需要在最后打開值。 作為默認值,您可以通過調用orElse返回0.0

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM