成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Java Stream魔法:List秒變Map,重復鍵值巧應對

開發 前端
在 Java 編程的廣闊世界里,將 List 轉換為 Map 是一項極為常見且基礎的操作,而 Java Stream API 的出現,為這一操作注入了新的活力,使其變得更加簡潔高效。通過使用Collectors.toMap()方法,我們能夠輕松地實現 List 到 Map 的轉換,滿足各種業務場景的需求。

一、Stream API 初相識

圖片圖片

在 Java 8 的世界里,Stream API 無疑是一顆璀璨的明星,為我們處理集合數據帶來了前所未有的便捷。以往,我們在操作集合時,常常需要編寫冗長的循環和復雜的條件判斷,代碼不僅繁瑣,而且可讀性欠佳。但 Stream API 的出現,徹底改變了這一局面。它以一種更為簡潔、高效的方式,讓我們能夠輕松地對集合進行過濾、映射、排序等操作,就像給我們的代碼插上了翅膀,使其更加優雅和強大。

Stream API 就像是一條神奇的流水線,集合中的元素就像流水線上的產品,我們可以在這條流水線上對元素進行各種加工處理。它支持鏈式調用,多個操作可以一氣呵成,讓代碼變得簡潔明了,就像在講述一個清晰的故事。而且,Stream API 還支持并行處理,能充分利用多核處理器的優勢,大大提高處理效率,在面對海量數據時,其優勢尤為明顯。

二、List 華麗變身 Map

圖片圖片

(一)基礎轉換操作

了解了 Stream API 的強大之處后,我們就來看看如何利用它將 List 轉換為 Map。在 Java 中,使用 Stream API 的 Collectors.toMap () 方法可以輕松實現這一轉換。下面通過一個具體的代碼示例來詳細說明。

假設我們有一個包含用戶信息的 List,每個用戶對象包含 id、name 和 age 等屬性,現在我們想將這個 List 轉換為以用戶 id 為鍵,用戶對象為值的 Map。代碼如下:

import java.util.*;import java.util.stream.Collectors;class User {private Integer id;private String name;private Integer age;public User(Integer id, String name, Integer age) {this.id = id;this.name = name;this.age = age;}public Integer getId() {return id;}public String getName() {return name;}public Integer getAge() {return age;}@Overridepublic String toString() {return "User{" +"id=" + id +", name='" + name + '\'' +", age=" + age +'}';}}public class ListToMapExample {public static void main(String[] args) {// 創建一個包含用戶信息的ListList<User> userList = new ArrayList<>();userList.add(new User(1, "Alice", 25));userList.add(new User(2, "Bob", 30));userList.add(new User(3, "Charlie", 28));// 使用Stream API將List轉換為MapMap<Integer, User> userMap = userList.stream().collect(Collectors.toMap(User::getId,  // 提取用戶id作為Map的鍵Function.identity()  // 直接使用用戶對象作為Map的值));// 輸出轉換后的MapuserMap.forEach((id, user) -> System.out.println("id: " + id + ", user: " + user));}}

在上述代碼中,Collectors.toMap()方法接收兩個參數:第一個參數User::getId是一個函數,用于從用戶對象中提取 id 作為 Map 的鍵;第二個參數Function.identity()表示直接使用用戶對象作為 Map 的值。通過這種方式,我們成功地將 List 轉換為了 Map。

(二)實際場景應用

在實際項目中,將 List 轉換為 Map 有著廣泛的應用場景。比如,在一個電商系統中,我們從數據庫中查詢出所有商品的信息,存儲在一個 List 中。如果我們需要根據商品 id 快速查找商品信息,就可以將這個 List 轉換為以商品 id 為鍵,商品對象為值的 Map,這樣在后續的操作中,通過商品 id 獲取商品信息的時間復雜度將從 O (n) 降低到 O (1),大大提高了查詢效率。

再比如,在處理日志數據時,我們可能會將日志信息存儲在 List 中,每一條日志記錄包含時間、日志級別、日志內容等信息。如果我們想要根據日志級別對日志進行分組統計,就可以將 List 轉換為以日志級別為鍵,包含該級別日志記錄的 List 為值的 Map,然后對每個分組進行相應的統計操作。

三、解決重復鍵值的挑戰

圖片圖片

在進行 List 到 Map 的轉換時,我們常常會遇到一個棘手的問題 —— 重復鍵值。由于 Map 的特性要求鍵必須唯一,當 List 中存在多個元素的鍵值相同時,直接使用Collectors.toMap()方法就會拋出IllegalStateException異常,提示 “Duplicate key”。這就好比我們要把一群人按照身份證號(假設鍵為身份證號)分組,而如果出現了兩個相同的身份證號,系統就會陷入混亂,不知道該如何處理。接下來,我們就一起探討一下應對這個挑戰的策略。

(一)拋出異常策略

默認情況下,當遇到重復鍵值時,Collectors.toMap()方法會拋出IllegalStateException異常。這是因為在大多數情況下,重復鍵值可能意味著數據存在錯誤或不一致性,系統無法自動決定如何處理這些重復的鍵值。例如,在上述用戶信息的例子中,如果有兩個用戶的 id 相同,這顯然是不符合業務邏輯的,拋出異常可以及時提醒開發者去檢查和修正數據。

(二)自定義合并策略

當我們確定重復鍵值是合理的業務情況,并且需要對其進行處理時,就可以使用Collectors.toMap()方法的另一個重載版本,它接收三個參數:鍵映射函數、值映射函數以及合并函數。通過自定義合并函數,我們可以靈活地處理重復鍵值的情況。

  • 保留舊值

保留舊值是指當遇到重復鍵時,不更新原有的值,保持 Map 中已存在的值不變。在一些場景中,我們希望優先保留最早出現的數據,因為它可能具有更高的優先級或更重要的信息。比如在記錄用戶的登錄歷史時,我們更關注用戶首次登錄的時間,所以當出現重復的用戶 id 時,保留首次登錄時間,忽略后續相同 id 的登錄時間記錄。

import java.util.*;import java.util.stream.Collectors;class User {private Integer id;private String name;private Integer age;public User(Integer id, String name, Integer age) {this.id = id;this.name = name;this.age = age;}public Integer getId() {return id;}public String getName() {return name;}public Integer getAge() {return age;}@Overridepublic String toString() {return "User{" +"id=" + id +", name='" + name + '\'' +", age=" + age +'}';}}public class ListToMapMergeExample {public static void main(String[] args) {List<User> userList = new ArrayList<>();userList.add(new User(1, "Alice", 25));userList.add(new User(1, "Bob", 30)); // 重復的idMap<Integer, User> userMap = userList.stream().collect(Collectors.toMap(User::getId,Function.identity(),(existing, replacement) -> existing // 保留舊值));userMap.forEach((id, user) -> System.out.println("id: " + id + ", user: " + user));}}

在上述代碼中,合并函數(existing, replacement) -> existing表示當遇到重復鍵時,直接返回已存在的值(即保留舊值)。運行這段代碼,我們會發現 Map 中最終保留的是第一個用戶 “Alice” 的信息,而第二個用戶 “Bob” 的信息被忽略了。

  • 選擇新值

選擇新值策略則與保留舊值相反,當遇到重復鍵時,使用新的值替換 Map 中已有的值。在某些場景下,新的數據可能更具有時效性或準確性,我們需要及時更新 Map 中的值。比如在實時更新用戶的在線狀態時,新的狀態信息更能反映用戶當前的實際情況,所以當出現重復的用戶 id 時,用新的在線狀態信息替換舊的。

import java.util.*;import java.util.stream.Collectors;class User {private Integer id;private String name;private Integer age;public User(Integer id, String name, Integer age) {this.id = id;this.name = name;this.age = age;}public Integer getId() {return id;}public String getName() {return name;}public Integer getAge() {return age;}@Overridepublic String toString() {return "User{" +"id=" + id +", name='" + name + '\'' +", age=" + age +'}';}}public class ListToMapMergeExample {public static void main(String[] args) {List<User> userList = new ArrayList<>();userList.add(new User(1, "Alice", 25));userList.add(new User(1, "Bob", 30)); // 重復的idMap<Integer, User> userMap = userList.stream().collect(Collectors.toMap(User::getId,Function.identity(),(existing, replacement) -> replacement // 選擇新值));userMap.forEach((id, user) -> System.out.println("id: " + id + ", user: " + user));}}

這里的合并函數(existing, replacement) -> replacement表示當鍵重復時,返回新的值。運行代碼后,Map 中最終保留的是第二個用戶 “Bob” 的信息,“Alice” 的信息被替換掉了。

  • 合并值

除了保留舊值和選擇新值,我們還可以將重復鍵的值進行合并。這種策略適用于需要對重復數據進行匯總或整合的場景。例如,我們有一個商品銷售記錄的 List,每個記錄包含商品 id、銷售數量和銷售金額等信息。當將這個 List 轉換為以商品 id 為鍵的 Map 時,如果存在相同商品 id 的記錄,我們可以將銷售數量和銷售金額進行累加,以得到該商品的總銷售數量和總銷售金額。

import java.util.*;import java.util.stream.Collectors;class SaleRecord {private Integer productId;private Integer quantity;private Double amount;public SaleRecord(Integer productId, Integer quantity, Double amount) {this.productId = productId;this.quantity = quantity;this.amount = amount;}public Integer getProductId() {return productId;}public Integer getQuantity() {return quantity;}public Double getAmount() {return amount;}@Overridepublic String toString() {return "SaleRecord{" +"productId=" + productId +", quantity=" + quantity +", amount=" + amount +'}';}}public class ListToMapMergeValueExample {public static void main(String[] args) {List<SaleRecord> saleRecordList = new ArrayList<>();saleRecordList.add(new SaleRecord(1, 5, 100.0));saleRecordList.add(new SaleRecord(1, 3, 60.0)); // 重復的productIdMap<Integer, SaleRecord> saleRecordMap = saleRecordList.stream().collect(Collectors.toMap(SaleRecord::getProductId,Function.identity(),(existing, replacement) -> new SaleRecord(existing.getProductId(),existing.getQuantity() + replacement.getQuantity(),existing.getAmount() + replacement.getAmount())));saleRecordMap.forEach((id, record) -> System.out.println("productId: " + id + ", record: " + record));}}

在這個例子中,合并函數創建了一個新的SaleRecord對象,將重復鍵的商品數量和銷售金額進行了累加。運行代碼后,我們可以看到 Map 中對應商品 id 的記錄是合并后的結果,包含了該商品的總銷售數量和總銷售金額 。如果是字符串類型的值,也可以進行拼接操作。比如有一個包含用戶興趣愛好的 List,每個用戶對象包含 id 和興趣愛好字段,當轉換為 Map 時,若有相同 id 的用戶,將他們的興趣愛好拼接起來,用逗號分隔。代碼如下:

import java.util.*;import java.util.stream.Collectors;class UserHobby {private Integer id;private String hobby;public UserHobby(Integer id, String hobby) {this.id = id;this.hobby = hobby;}public Integer getId() {return id;}public String getHobby() {return hobby;}@Overridepublic String toString() {return "UserHobby{" +"id=" + id +", hobby='" + hobby + '\'' +'}';}}public class ListToMapMergeStringExample {public static void main(String[] args) {List<UserHobby> userHobbyList = new ArrayList<>();userHobbyList.add(new UserHobby(1, "Reading"));userHobbyList.add(new UserHobby(1, "Swimming")); // 重復的idMap<Integer, String> hobbyMap = userHobbyList.stream().collect(Collectors.toMap(UserHobby::getId,UserHobby::getHobby,(existing, replacement) -> existing + ", " + replacement));hobbyMap.forEach((id, hobby) -> System.out.println("id: " + id + ", hobby: " + hobby));}}

在這個代碼中,合并函數將重復 id 的用戶興趣愛好進行了拼接,中間用逗號分隔,最終得到了一個包含每個用戶所有興趣愛好的 Map 。通過這些自定義合并策略,我們能夠根據具體的業務需求,靈活、有效地處理 List 轉換為 Map 時遇到的重復鍵值問題,讓我們的代碼更加健壯和智能。

四、綜合實戰演練

圖片圖片

(一)復雜數據結構轉換

在實際應用中,我們面對的數據結構往往更加復雜。接下來,通過一個復雜的數據結構示例,展示如何將其轉換為 Map 并處理重復鍵值。假設我們有一個電商系統,其中包含訂單信息。每個訂單包含訂單 id、客戶信息、訂單明細列表,而訂單明細又包含商品信息、商品數量和商品單價。現在我們要將一個包含多個訂單的 List 轉換為以訂單 id 為鍵,訂單總金額為值的 Map,并且要處理可能出現的重復訂單 id(雖然在實際業務中訂單 id 通常是唯一的,但為了演示處理重復鍵值的情況,這里假設存在這種可能性)。代碼如下:

import java.util.*;import java.util.stream.Collectors;// 商品類class Product {private String productName;private double unitPrice;public Product(String productName, double unitPrice) {this.productName = productName;this.unitPrice = unitPrice;}public String getProductName() {return productName;}public double getUnitPrice() {return unitPrice;}}// 訂單明細類class OrderItem {private Product product;private int quantity;public OrderItem(Product product, int quantity) {this.product = product;this.quantity = quantity;}public Product getProduct() {return product;}public int getQuantity() {return quantity;}// 計算訂單明細的金額public double calculateAmount() {return product.getUnitPrice() * quantity;}}// 客戶類class Customer {private String customerName;private String contactNumber;public Customer(String customerName, String contactNumber) {this.customerName = customerName;this.contactNumber = contactNumber;}public String getCustomerName() {return customerName;}public String getContactNumber() {return contactNumber;}}// 訂單類class Order {private int orderId;private Customer customer;private List<OrderItem> orderItems;public Order(int orderId, Customer customer, List<OrderItem> orderItems) {this.orderId = orderId;this.customer = customer;this.orderItems = orderItems;}public int getOrderId() {return orderId;}public Customer getCustomer() {return customer;}public List<OrderItem> getOrderItems() {return orderItems;}// 計算訂單總金額public double calculateTotalAmount() {return orderItems.stream().mapToDouble(OrderItem::calculateAmount).sum();}}public class ComplexListToMapExample {public static void main(String[] args) {// 創建商品對象Product product1 = new Product("Laptop", 1000.0);Product product2 = new Product("Mouse", 50.0);// 創建訂單明細對象OrderItem orderItem1 = new OrderItem(product1, 2);OrderItem orderItem2 = new OrderItem(product2, 3);// 創建客戶對象Customer customer1 = new Customer("Alice", "123456789");// 創建訂單對象Order order1 = new Order(1, customer1, Arrays.asList(orderItem1, orderItem2));Order order2 = new Order(1, customer1, Arrays.asList(orderItem1)); // 重復的訂單idList<Order> orderList = new ArrayList<>();orderList.add(order1);orderList.add(order2);// 使用Stream API將List轉換為Map,并處理重復鍵值(這里選擇合并訂單總金額)Map<Integer, Double> orderTotalAmountMap = orderList.stream().collect(Collectors.toMap(Order::getOrderId,Order::calculateTotalAmount,(existingAmount, newAmount) -> existingAmount + newAmount));orderTotalAmountMap.forEach((orderId, totalAmount) -> System.out.println("orderId: " + orderId + ", totalAmount: " + totalAmount));}}

在上述代碼中,首先定義了多個類來表示復雜的數據結構,包括Product(商品)、OrderItem(訂單明細)、Customer(客戶)和Order(訂單)。然后創建了一些示例數據,并將其存儲在orderList中。最后,使用 Stream API 將orderList轉換為以訂單 id 為鍵,訂單總金額為值的 Map。在轉換過程中,通過自定義合并函數(existingAmount, newAmount) -> existingAmount + newAmount來處理可能出現的重復訂單 id,將重復訂單的總金額進行合并。

(二)結合其他 Stream 操作

在將 List 轉換為 Map 的過程中,我們還可以結合其他 Stream 操作,實現更強大的數據處理功能。比如,在上述訂單的例子中,我們可以先對訂單列表進行過濾,只選擇特定客戶的訂單,然后再進行轉換。同時,還可以對訂單明細進行映射,提取出商品名稱,再進行后續處理。代碼如下:

import java.util.*;import java.util.stream.Collectors;// 商品類class Product {private String productName;private double unitPrice;public Product(String productName, double unitPrice) {this.productName = productName;this.unitPrice = unitPrice;}public String getProductName() {return productName;}public double getUnitPrice() {return unitPrice;}}// 訂單明細類class OrderItem {private Product product;private int quantity;public OrderItem(Product product, int quantity) {this.product = product;this.quantity = quantity;}public Product getProduct() {return product;}public int getQuantity() {return quantity;}// 計算訂單明細的金額public double calculateAmount() {return product.getUnitPrice() * quantity;}}// 客戶類class Customer {private String customerName;private String contactNumber;public Customer(String customerName, String contactNumber) {this.customerName = customerName;this.contactNumber = contactNumber;}public String getCustomerName() {return customerName;}public String getContactNumber() {return contactNumber;}}// 訂單類class Order {private int orderId;private Customer customer;private List<OrderItem> orderItems;public Order(int orderId, Customer customer, List<OrderItem> orderItems) {this.orderId = orderId;this.customer = customer;this.orderItems = orderItems;}public int getOrderId() {return orderId;}public Customer getCustomer() {return customer;}public List<OrderItem> getOrderItems() {return orderItems;}// 計算訂單總金額public double calculateTotalAmount() {return orderItems.stream().mapToDouble(OrderItem::calculateAmount).sum();}}public class ComplexListToMapWithOtherStreamOpsExample {public static void main(String[] args) {// 創建商品對象Product product1 = new Product("Laptop", 1000.0);Product product2 = new Product("Mouse", 50.0);// 創建訂單明細對象OrderItem orderItem1 = new OrderItem(product1, 2);OrderItem orderItem2 = new OrderItem(product2, 3);// 創建客戶對象Customer customer1 = new Customer("Alice", "123456789");Customer customer2 = new Customer("Bob", "987654321");// 創建訂單對象Order order1 = new Order(1, customer1, Arrays.asList(orderItem1, orderItem2));Order order2 = new Order(2, customer2, Arrays.asList(orderItem1));List<Order> orderList = new ArrayList<>();orderList.add(order1);orderList.add(order2);// 結合過濾和映射操作,將特定客戶(這里是Alice)的訂單轉換為以訂單id為鍵,包含訂單中所有商品名稱的List為值的MapMap<Integer, List<String>> orderProductNamesMap = orderList.stream().filter(order -> "Alice".equals(order.getCustomer().getCustomerName())).collect(Collectors.toMap(Order::getOrderId,order -> order.getOrderItems().stream().map(orderItem -> orderItem.getProduct().getProductName()).collect(Collectors.toList())));orderProductNamesMap.forEach((orderId, productNames) -> {System.out.println("orderId: " + orderId);System.out.println("Product Names: " + productNames);});}}

在這段代碼中,首先使用filter操作篩選出客戶名為 “Alice” 的訂單,然后在Collectors.toMap的第二個參數中,使用map操作提取每個訂單中所有訂單明細的商品名稱,并通過collect(Collectors.toList())將這些商品名稱收集到一個 List 中,最終得到一個以訂單 id 為鍵,包含訂單中所有商品名稱的 List 為值的 Map。通過這樣的方式,我們可以靈活地組合各種 Stream 操作,滿足復雜的數據處理需求,讓 Java Stream API 在實際應用中發揮出更大的威力。

五、總結與展望

圖片圖片

在 Java 編程的廣闊世界里,將 List 轉換為 Map 是一項極為常見且基礎的操作,而 Java Stream API 的出現,為這一操作注入了新的活力,使其變得更加簡潔高效。通過使用Collectors.toMap()方法,我們能夠輕松地實現 List 到 Map 的轉換,滿足各種業務場景的需求。

在處理重復鍵值這一關鍵問題時,我們有多種策略可供選擇。拋出異常策略能幫助我們及時發現數據中的潛在問題,確保數據的準確性和一致性;而自定義合并策略則賦予了我們更大的靈活性,根據不同的業務邏輯,我們可以選擇保留舊值、選擇新值或者合并值,讓代碼更加貼合實際業務需求。

通過復雜數據結構轉換和結合其他 Stream 操作的實戰演練,我們更加深入地領略了 Stream API 的強大功能和無限潛力。它不僅能處理簡單的數據轉換,還能在復雜的數據結構和多樣化的業務邏輯中發揮重要作用,結合其他 Stream 操作,如過濾、映射等,Stream API 能夠實現更加復雜的數據處理任務,為我們的開發工作提供了極大的便利 。

希望大家在今后的 Java 開發中,能夠大膽地運用 Stream API 來處理 List 到 Map 的轉換以及重復鍵值的問題。不斷探索 Stream API 的更多用法和技巧,將其融入到日常的項目開發中,相信它一定會為你的代碼帶來更高的效率和更好的可讀性,讓你的開發工作事半功倍!

責任編輯:武曉燕 來源: 程序員conan
相關推薦

2010-09-14 12:30:46

無線網絡管理

2009-07-09 17:06:28

2014-02-11 15:31:33

LinuxWindows 8

2022-08-22 14:48:59

if/else抽象

2010-06-07 13:20:39

MySQL插入處理重復

2024-01-11 08:03:52

程序圖片優化

2023-03-15 17:37:26

Java8ListMap

2023-08-25 13:32:05

COBOLJavaAI

2015-03-24 13:53:26

程序員程序員精神崩潰程序員建議

2025-03-06 07:44:36

2010-04-07 15:13:42

中間件BPMSOA

2012-03-14 11:13:27

Java

2015-08-14 10:03:52

Windows 10美化工具

2024-11-05 10:24:50

2017-12-03 21:47:07

開源工具JavaScript

2015-12-03 10:03:38

夜神

2013-09-11 09:49:18

Java數組集合

2010-04-14 10:52:01

2017-03-19 15:51:47

人工神經網絡

2015-12-04 10:25:50

VR拍照谷歌
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 亚洲欧美在线观看视频 | 中文成人在线 | 国产电影一区二区在线观看 | 另类亚洲视频 | 九九久久在线看 | 91精品国产一区二区三区香蕉 | 在线毛片网 | 国产精品日产欧美久久久久 | 欧美激情一区二区三区 | 99国产精品久久久 | 国产精品伦理一区二区三区 | 日韩欧美一区二区三区免费看 | 亚洲一区中文字幕 | 色在线视频网站 | 欧美一级在线观看 | av永久 | 男女羞羞视频在线 | 成人免费视频播放 | 色综网| 午夜日韩视频 | 成人亚洲综合 | 91在线资源 | 精品国产乱码一区二区三区a | 成人在线精品 | 香蕉婷婷 | 成人乱人乱一区二区三区软件 | 精品不卡 | 久久久久免费精品国产小说色大师 | 国产成人福利在线 | 免费成人毛片 | 成人免费观看视频 | 亚洲精品第一国产综合野 | 久久久久成人精品免费播放动漫 | 国产精品91网站 | 久久精品国产一区 | 午夜欧美一区二区三区在线播放 | 国产精品日产欧美久久久久 | 亚洲一区二区三区高清 | 国产精品日韩欧美一区二区三区 | 国产一区欧美 | 91免费电影 |