电商购物车的核心需求之一是按照用户添加商品的先后顺序展示商品列表,同时需要定期清理长时间未操作、已经过期的商品,避免无效数据占用存储资源。LinkedHashMap作为Java集合框架中兼具哈希表高效查询和链表有序特性的数据结构,能够很好地满足这两个需求。

LinkedHashMap的核心特性
LinkedHashMap继承自HashMap,内部维护了一个双向链表,默认情况下会按照元素的插入顺序来维护链表顺序,也可以设置为按照访问顺序维护。它的核心特性如下:
- 插入顺序维护:默认构造的LinkedHashMap会记录元素插入的先后顺序,遍历时按照插入顺序输出元素
- 访问顺序维护:通过构造参数
accessOrder设置为true后,每次访问元素都会将该元素移到链表尾部,最近访问的元素会在链表末尾 - 支持元素移除回调:可以重写
removeEldestEntry方法,在添加新元素时判断是否需要移除最旧的元素
购物车商品模型设计
首先我们需要定义购物车中的商品实体类,包含商品的基本信息、添加时间、最后操作时间等字段,用于后续的顺序判断和过期判断:
import java.io.Serializable;
import java.util.Date;
/**
* 购物车商品实体类
*/
public class CartItem implements Serializable {
// 商品ID
private String productId;
// 商品名称
private String productName;
// 商品数量
private Integer quantity;
// 商品单价
private Double price;
// 商品添加时间
private Date addTime;
// 最后操作时间(修改数量、选中状态等操作时更新)
private Date lastOperateTime;
public CartItem(String productId, String productName, Integer quantity, Double price) {
this.productId = productId;
this.productName = productName;
this.quantity = quantity;
this.price = price;
this.addTime = new Date();
this.lastOperateTime = new Date();
}
// getter和setter方法省略
}
基于LinkedHashMap实现购物车核心逻辑
我们使用LinkedHashMap作为购物车的核心存储容器,键为商品ID,值为购物车商品实体,默认按照插入顺序维护,保证商品展示的顺序和用户添加顺序一致:
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* 电商购物车实现类
*/
public class ShoppingCart {
// 购物车商品存储容器,键为商品ID,值为购物车商品
private LinkedHashMap<String, CartItem> cartItems;
// 商品过期时间,单位毫秒,这里设置为30分钟
private static final long EXPIRE_TIME = 30 * 60 * 1000;
public ShoppingCart() {
// 初始化LinkedHashMap,默认按照插入顺序维护
cartItems = new LinkedHashMap<>();
}
/**
* 添加商品到购物车
* @param item 购物车商品实体
*/
public void addItem(CartItem item) {
// 如果商品已存在,更新数量和最后操作时间
if (cartItems.containsKey(item.getProductId())) {
CartItem existItem = cartItems.get(item.getProductId());
existItem.setQuantity(existItem.getQuantity() + item.getQuantity());
existItem.setLastOperateTime(new Date());
} else {
// 商品不存在,直接添加
cartItems.put(item.getProductId(), item);
}
}
/**
* 获取有序的购物车商品列表
* @return 按照添加顺序排序的购物车商品列表
*/
public LinkedHashMap<String, CartItem> getOrderedCartItems() {
// 先清理过期商品
removeExpiredItems();
return cartItems;
}
/**
* 清理过期的购物车商品
*/
private void removeExpiredItems() {
Iterator<Map.Entry<String, CartItem>> iterator = cartItems.entrySet().iterator();
Date now = new Date();
while (iterator.hasNext()) {
Map.Entry<String, CartItem> entry = iterator.next();
CartItem item = entry.getValue();
// 判断最后操作时间是否超过过期时间
if (now.getTime() - item.getLastOperateTime().getTime() > EXPIRE_TIME) {
iterator.remove();
}
}
}
/**
* 修改购物车商品数量
* @param productId 商品ID
* @param quantity 新的数量
*/
public void updateItemQuantity(String productId, Integer quantity) {
if (cartItems.containsKey(productId)) {
CartItem item = cartItems.get(productId);
item.setQuantity(quantity);
item.setLastOperateTime(new Date());
}
}
/**
* 从购物车移除商品
* @param productId 商品ID
*/
public void removeItem(String productId) {
cartItems.remove(productId);
}
}
功能测试验证
我们编写测试代码验证购物车的有序展示和过期处理功能是否正常工作:
import java.util.Map;
public class CartTest {
public static void main(String[] args) throws InterruptedException {
ShoppingCart cart = new ShoppingCart();
// 添加三个商品,模拟用户依次添加
CartItem item1 = new CartItem("p001", "无线鼠标", 1, 89.9);
Thread.sleep(1000);
CartItem item2 = new CartItem("p002", "机械键盘", 1, 299.9);
Thread.sleep(1000);
CartItem item3 = new CartItem("p003", "显示器", 1, 1299.9);
cart.addItem(item1);
cart.addItem(item2);
cart.addItem(item3);
// 打印当前购物车商品,验证顺序
System.out.println("初始购物车商品顺序:");
for (Map.Entry<String, CartItem> entry : cart.getOrderedCartItems().entrySet()) {
System.out.println("商品ID:" + entry.getKey() + ",商品名称:" + entry.getValue().getProductName());
}
// 模拟修改第一个商品的数量,更新其最后操作时间
cart.updateItemQuantity("p001", 2);
System.out.println("修改p001数量后,购物车商品顺序:");
for (Map.Entry<String, CartItem> entry : cart.getOrderedCartItems().entrySet()) {
System.out.println("商品ID:" + entry.getKey() + ",商品名称:" + entry.getValue().getProductName());
}
// 模拟等待超过过期时间,这里为了测试方便,临时修改过期时间为3秒
// 实际使用中不需要这行代码,直接用默认的30分钟即可
ShoppingCart.EXPIRE_TIME = 3000;
Thread.sleep(4000);
System.out.println("等待过期后,购物车商品顺序:");
for (Map.Entry<String, CartItem> entry : cart.getOrderedCartItems().entrySet()) {
System.out.println("商品ID:" + entry.getKey() + ",商品名称:" + entry.getValue().getProductName());
}
}
}
实际场景优化建议
上述实现是基础版本,在实际电商场景中还可以做以下优化:
- 如果是分布式场景,可以将LinkedHashMap替换为Redis的有序结构,比如ZSet,同时利用Redis的过期机制处理商品过期
- 可以结合定时任务定期清理购物车中的过期商品,避免每次获取购物车列表时才清理,减少接口响应时间
- 可以在
removeExpiredItems方法中添加过期商品的持久化逻辑,比如将过期商品记录到用户的历史购物车中,方便用户后续找回 - 如果用户有调整商品顺序的需求,可以结合访问顺序模式,将用户手动调整顺序的操作视为访问,更新元素在链表中的位置
需要注意的是,LinkedHashMap本身不是线程安全的,如果在多线程场景下使用,需要添加同步机制,或者使用Collections.synchronizedMap包装LinkedHashMap,避免并发修改导致的异常。
LinkedHashMap电商购物车有序展示商品过期处理修改时间:2026-07-09 12:39:36