簡體   English   中英

java 8,lambda,對象復制:創建規范化對象的新列表

[英]java 8, lambda , Objects copying: Creating a new list of Normalized objects

從 REST 服務中,我將得到員工列表的響應。 其中可能包含以下定義的同一員工的多個地址。

[Employee{empId=1, name='Emp1', address='Emp1 Address1'},
Employee{empId=1, name='Emp1', address='Emp1 Address 2'},
Employee{empId=2, name='Emp2', address='Emp2 Address 1'}]

通過創建另一個列表,即List<EmployeeNormalized > ,需要以標准化方式處理上述響應,如下所述。

[EmployeeNormalized{empId=1, name='Emp1',
addresses=[Emp1 Address1, Emp1 Address 2]},
EmployeeNormalized{empId=2, name='Emp2', addresses=[Emp2 Address 1]}]

代碼片段:

class Employee {
    private int empId;
    private String name;
    private String address;

    public Employee(int empId, String name, String address) {
        this.empId = empId;
        this.name = name;
        this.address = address;
    }
   // Setters and Getters
}

class EmployeeNormalized {
    private int empId;
    private String name;
    private List<String> addresses;

    public EmployeeNormalized(int empId, String name, List<String> address) {
        this.empId = empId;
        this.name = name;
        this.addresses = address;
    }
   // Setters and Getters
} 

List<EmployeeNormalized >必須包含唯一的員工對象,並且EmployeeNormalized class 中的List<String>應該包含該員工的所有地址。

如何創建這種標准化形式的列表?

Stream 解決方案:

public class Normalize {

    public static void main(String[] args) {
        List<Employee> employees = new ArrayList<>();
        employees.add(new Employee(1, "Emp1", "Address 1"));
        employees.add(new Employee(1, "Emp1", "Address 2"));
        employees.add(new Employee(2, "Emp2", "Address 3"));
        List<EmployeeNormalized> employeeNormalizedList = employees.stream()
                .map(new Function<Employee, EmployeeNormalized>() {

                    private final Map<Integer, EmployeeNormalized> employeeIdMap = new HashMap<>();

                    @Override
                    public EmployeeNormalized apply(Employee employee) {
                        EmployeeNormalized normalized = this.employeeIdMap.computeIfAbsent(employee.getEmpId(),
                                key -> new EmployeeNormalized(employee.getEmpId(), employee.getName(), new ArrayList<>()));
                        normalized.getAddresses().add(employee.getAddress());
                        return normalized;
                    }
                })
                .distinct()
                .collect(Collectors.toList());
        employeeNormalizedList.forEach(System.out::println);
    }
}

相當復雜,需要調用 distinct 來消除重復的實例。

我會 go 用於簡單的循環:

public class Normalize {

    public static void main(String[] args) {
        List<Employee> employees = new ArrayList<>();
        employees.add(new Employee(1, "Emp1", "Address 1"));
        employees.add(new Employee(1, "Emp1", "Address 2"));
        employees.add(new Employee(2, "Emp2", "Address 3"));

        Map<Integer, EmployeeNormalized> employeeIdMap = new HashMap<>();
        for (Employee employee : employees) {
            EmployeeNormalized normalized = employeeIdMap.computeIfAbsent(employee.getEmpId(), key -> new EmployeeNormalized(employee.getEmpId(), employee.getName(), new ArrayList<>()));
            normalized.getAddresses().add(employee.getAddress());
        }
        List<EmployeeNormalized> employeeNormalizedList = new ArrayList<>(employeeIdMap.values());
        employeeNormalizedList.forEach(System.out::println);
    }
}

基本上,這兩種解決方案都使用員工 ID 作為唯一標識符,並使用 map 實例作為 ID。 如果第一次遇到id,則創建實例並添加地址,如果已經有該id的實例,則獲取實例並添加地址。

這個任務可以用 Stream API 來解決,前提是有一些包裝類/記錄來表示一個(employeeId 和employeeName)。 即使是普通的ArrayList<Object>也可以用於此目的,但自 Java 16 以來引入record ,最好使用它們。

解決方案本身非常簡單:使用Collectors.groupingBy創建一個鍵,使用Collectors.mapping構建每個員工的地址列表,最后在EmployeeNormalized中加入鍵( employeeIdemployeeName )和地址值列表:

//
List<Employee> employees = .... ; // build employee list
List<EmployeeNormalized> normEmployees = employees
    .stream()
    .collect(Collectors.groupingBy(
        emp -> Arrays.asList(emp.getEmpId(), emp.getName()),
        LinkedHashMap::new, // maintain insertion order
        Collectors.mapping(Employee::getAddress, Collectors.toList())
    )) // Map<List<Object>, List<String>>
    .entrySet()
    .stream()
    .map(e -> new EmployeeNormalized(
        ((Integer) e.getKey().get(0)).intValue(), // empId
        (String) e.getKey().get(1),               // name
        e.getValue()
    ))
    .collect(Collectors.toList());

使用record允許維護類型安全的鍵而無需額外的轉換。 可以用一個小的包裝器 class 替換記錄,以表示一個帶有hashCode / equals方法的鍵,因為此 class 的實例用作中間 map 中的鍵。

// Java 16+
record EmpKey(int empId, String name) {}

List<EmployeeNormalized> normEmployees = employees
    .stream()
    .collect(Collectors.groupingBy(
        emp -> new EmpKey(emp.getEmpId(), emp.getName()),
        LinkedHashMap::new, // maintain insertion order
        Collectors.mapping(Employee::getAddress, Collectors.toList())
    )) // Map<List<Object>, List<String>>
    .entrySet()
    .stream()
    .map(e -> new EmployeeNormalized(
        e.getKey().empId(), e.getKey().name(), e.getValue()
    ))
    .collect(Collectors.toList());

暫無
暫無

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

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