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 分享