
在日常的数据处理中,我们经常会遇到需要从一个对象列表中提取唯一记录的场景。然而,这里的“唯一”可能并非指所有字段都完全相同,而是基于某个或某几个特定字段的组合。更进一步,当这些组合字段出现重复时,我们可能需要根据另一个字段(例如时间戳或版本号)来决定保留哪一条记录。
以员工数据为例,假设我们有一个Employee对象列表,其定义如下:
import lombok.Data;
import lombok.AllArgsConstructor;
import java.time.LocalDateTime;
@Data
@AllArgsConstructor
public class Employee {
private String firstName;
private String lastName;
private double salary;
private LocalDateTime getSalaryDate; // 更改为更具描述性的字段名
}该列表中可能存在多条记录拥有相同的firstName和lastName,但salary和getSalaryDate(获取薪资的日期)不同。例如:
List<Employee> employees = new ArrayList<>();
employees.add(new Employee("John", "Smith", 10, LocalDateTime.of(2022, 9, 1, 0, 0)));
employees.add(new Employee("John", "Smith", 20, LocalDateTime.of(2022, 10, 1, 0, 0)));
employees.add(new Employee("John", "Smith", 5, LocalDateTime.of(2022, 11, 1, 0, 0)));
employees.add(new Employee("Kelly", "Jones", 12, LocalDateTime.of(2022, 3, 1, 0, 0)));
employees.add(new Employee("Sara", "Kim", 21, LocalDateTime.of(2022, 3, 1, 0, 0)));
employees.add(new Employee("Sara", "Kim", 7, LocalDateTime.of(2022, 7, 1, 0, 0)));我们的目标是:对于每对唯一的firstName和lastName组合,只保留一条记录,且这条记录必须是getSalaryDate最新的那一条。
期望的输出结果应为:
立即学习“Java免费学习笔记(深入)”;
Java 8引入的Stream API为处理集合数据提供了强大而灵活的工具。针对上述问题,我们可以利用Collectors.toMap结合自定义的合并函数(merge function)来实现。
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
public class EmployeeFilterTutorial {
// Employee 类定义(同上,为了完整性再次列出)
@Data
@AllArgsConstructor
public static class Employee {
private String firstName;
private String lastName;
private double salary;
private LocalDateTime getSalaryDate;
}
public static void main(String[] args) {
List<Employee> employees = new ArrayList<>();
employees.add(new Employee("John", "Smith", 10, LocalDateTime.of(2022, 9, 1, 0, 0)));
employees.add(new Employee("John", "Smith", 20, LocalDateTime.of(2022, 10, 1, 0, 0)));
employees.add(new Employee("John", "Smith", 5, LocalDateTime.of(2022, 11, 1, 0, 0)));
employees.add(new Employee("Kelly", "Jones", 12, LocalDateTime.of(2022, 3, 1, 0, 0)));
employees.add(new Employee("Sara", "Kim", 21, LocalDateTime.of(2022, 3, 1, 0, 0)));
employees.add(new Employee("Sara", "Kim", 7, LocalDateTime.of(2022, 7, 1, 0, 0)));
Collection<Employee> filteredEmployees = employees.stream()
.collect(Collectors.toMap(
// Key Mapper: 组合 firstName 和 lastName 作为唯一键
employee -> employee.getFirstName() + employee.getLastName(),
// Value Mapper: 将 Employee 对象本身作为值
Function.identity(),
// Merge Function: 处理键冲突,保留 getSalaryDate 最新的 Employee
(existingEmployee, newEmployee) ->
existingEmployee.getSalaryDate().isAfter(newEmployee.getSalaryDate()) ? existingEmployee : newEmployee
))
.values(); // 从 Map 中获取所有值,即为过滤后的 Employee 集合
// 打印结果
filteredEmployees.forEach(System.out::println);
}
}Employee(firstName=John, lastName=Smith, salary=5.0, getSalaryDate=2022-11-01T00:00) Employee(firstName=Sara, lastName=Kim, salary=7.0, getSalaryDate=2022-07-01T00:00) Employee(firstName=Kelly, lastName=Jones, salary=12.0, getSalaryDate=2022-03-01T00:00)
可以看到,输出结果与我们的预期完全一致,对于每个独特的姓名组合,都只保留了拥有最新薪资获取日期的员工记录。
(e1, e2) -> {
if (e1.getSalaryDate() == null) return e2;
if (e2.getSalaryDate() == null) return e1;
return e1.getSalaryDate().isAfter(e2.getSalaryDate()) ? e1 : e2;
}通过本教程,我们学习了如何巧妙地运用Java Stream API中的Collectors.toMap,结合自定义的键映射和合并函数,来解决复杂的数据过滤和聚合问题。这种方法不仅代码简洁、可读性强,而且在处理大量数据时表现出良好的性能。掌握这种模式,将大大提升在Java中进行数据处理的效率和灵活性。
以上就是Java Stream API:高效处理列表数据,按组合键去重并选择最新记录的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号