的高效方法
" />
核心思路
问题的关键在于如何处理嵌套的集合结构。我们需要将 Trip 对象中的 Employee 列表扁平化,以便能够基于 empId 进行分组。这可以通过引入一个辅助对象来实现,该对象同时持有 empId 和 Trip 实例的引用。
辅助对象:TripEmployee (Java 16+ record)
从 Java 16 开始,可以使用 record 关键字来简洁地定义一个不可变的数据类,非常适合作为辅助对象。
public record TripEmployee(String empId, Trip trip) {}如果使用 Java 8,则需要创建一个普通的 class。
立即学习“Java免费学习笔记(深入)”;
Java 8 实现 (class)
public class TripEmployee {
private String empId;
private Trip trip;
public TripEmployee(String empId, Trip trip) {
this.empId = empId;
this.trip = trip;
}
public String getEmpId() {
return empId;
}
public Trip getTrip() {
return trip;
}
}代码实现
以下是使用 Stream API 实现转换的代码示例:
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
public class TripMappingExample {
@Data
@NoArgsConstructor
@AllArgsConstructor
static class Trip {
private Date startTime;
private Date endTime;
List<Employee> empList;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
static class Employee {
private String name;
private String empId;
}
public record TripEmployee(String empId, Trip trip) {}
public static void main(String[] args) {
// 示例数据
List<Trip> trips = new ArrayList<>();
// 创建一些 Employee 对象
Employee emp1 = new Employee("Alice", "E123");
Employee emp2 = new Employee("Bob", "E456");
Employee emp3 = new Employee("Charlie", "E123"); // 故意重复一个 empId
// 创建包含 Employee 列表的 Trip 对象
Trip trip1 = new Trip(new Date(), new Date(), List.of(emp1, emp2));
Trip trip2 = new Trip(new Date(), new Date(), List.of(emp2, emp3));
trips.add(trip1);
trips.add(trip2);
// 使用 Stream API 进行转换
Map<String, List<Trip>> empMap = trips.stream()
.flatMap(trip -> trip.getEmpList().stream()
.map(emp -> new TripEmployee(emp.getEmpId(), trip)))
.collect(Collectors.groupingBy(
TripEmployee::empId,
Collectors.mapping(TripEmployee::trip,
Collectors.toList())));
// 打印结果
empMap.forEach((empId, tripList) -> {
System.out.println("Employee ID: " + empId);
tripList.forEach(trip -> System.out.println(" Trip: " + trip));
});
}
}代码解释
- trips.stream(): 创建 Trip 对象的 Stream。
- flatMap(trip -> trip.getEmpList().stream().map(emp -> new TripEmployee(emp.getEmpId(), trip))): 对于每个 Trip 对象,获取其 Employee 列表,并将其转换为 Stream<Employee>。然后,使用 map 操作将每个 Employee 对象转换为 TripEmployee 对象,其中包含 empId 和原始的 Trip 对象。flatMap 将所有这些 Stream<TripEmployee> 合并成一个单一的 Stream<TripEmployee>。
- collect(Collectors.groupingBy(TripEmployee::empId, Collectors.mapping(TripEmployee::trip, Collectors.toList()))): 使用 groupingBy 收集器,根据 TripEmployee 对象的 empId 进行分组。mapping 收集器作为 groupingBy 的下游收集器,将每个分组中的 TripEmployee 对象转换为 Trip 对象,并将它们收集到一个列表中。
注意事项
- 确保项目中包含 Lombok 依赖,以便使用 @Data, @NoArgsConstructor, @AllArgsConstructor 等注解。
- 如果使用 Java 8,请将 record 替换为等效的 class 实现。
- 如果 empId 为 null 或空字符串,则 groupingBy 操作可能会导致 NullPointerException。在实际应用中,请根据需要添加空值检查。
总结
本文提供了一种使用 Java 8 Stream API 将 List<Trip> 转换为 Map<String, List<Trip>> 的高效方法。通过引入辅助对象并结合 flatMap、groupingBy 和 mapping 等 Stream API 的关键操作,可以简洁而有效地实现数据转换。这种方法不仅提高了代码的可读性,而且充分利用了 Stream API 的并行处理能力,可以显著提升性能。










