Java 8 Stream API:使用 List 生成 Map<String, List> 的高效方法

Java 8 Stream API:使用 List 生成 Map<String, List> 的高效方法 的高效方法 ” />

本文将深入探讨如何使用 Java 8 Stream API 将一个 List 转换为 map>。目标是将每个 Employee 的 empId 与包含该 Employee 的所有 Trip 对象关联起来。

核心思路

问题的关键在于如何处理嵌套的集合结构。我们需要将 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));         });     } }

代码解释

  1. trips.stream(): 创建 Trip 对象的 Stream。
  2. flatMap(trip -> trip.getEmpList().stream().map(emp -> new TripEmployee(emp.getEmpId(), trip))): 对于每个 Trip 对象,获取其 Employee 列表,并将其转换为 Stream。然后,使用 map 操作将每个 Employee 对象转换为 TripEmployee 对象,其中包含 empId 和原始的 Trip 对象。flatMap 将所有这些 Stream 合并成一个单一的 Stream
  3. 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 转换为 Map> 的高效方法。通过引入辅助对象并结合 flatMap、groupingBy 和 mapping 等 Stream API 的关键操作,可以简洁而有效地实现数据转换。这种方法不仅提高了代码的可读性,而且充分利用了 Stream API 的并行处理能力,可以显著提升性能。

© 版权声明
THE END
喜欢就支持一下吧
点赞6 分享