如何使用Java Stream找出拥有全部主商品列表商品的顾客?
用Java Stream筛选拥有全部主商品的顾客
我是Java新手,现在有两个列表:
- 包含顾客及其购物车商品的顾客列表
- 动态变化的主商品列表
示例对象格式
Customer列表(JSON示例)
[ { "customerId": 123, "cartItems": [ { "itemId": "123-XYZ", "itemPrice": 200 }, { "itemId": "123-ABC", "itemPrice": 100 } ] }, { "customerId": 987, "cartItems": [ { "itemId": "987-XYZ", "itemPrice": 200 } ] } ]
注:顾客购物车中的itemId由顾客ID与商品名通过-分隔组成。
主商品列表(JSON示例)
[ { "itemName": "XYZ", "itemPrice": 200 }, { "itemName": "ABC", "itemPrice": 100 } ]
需求
筛选出拥有主商品列表中全部商品的顾客(主商品列表是动态变化的)。我已经能用普通for循环实现(代码如下),想知道怎么用Stream函数正确解决这个问题。
原for循环实现代码
for(Customer customer: customers) { List<Item> items = customer.getItems(); for(Item item: items) { if(item.getItemId().contains(masterListItems.getItemName()) & item.getItemPrice().equals(masterListItems.getItemPrice())) { System.out.println("Item found"); } } }
Stream解决方案
首先,为了高效对比,我们可以先把主商品列表转换成一个商品特征集合(用商品名和价格作为匹配依据),后续比对效率会更高。
步骤1:定义商品匹配特征类
Java 16+可以用record快速定义(自动生成equals、hashCode):
record MasterItem(String itemName, Integer itemPrice) {}
Java 16之前用普通类,需要手动重写equals和hashCode:
import java.util.Objects; class MasterItem { private String itemName; private Integer itemPrice; public MasterItem(String itemName, Integer itemPrice) { this.itemName = itemName; this.itemPrice = itemPrice; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; MasterItem that = (MasterItem) o; return Objects.equals(itemName, that.itemName) && Objects.equals(itemPrice, that.itemPrice); } @Override public int hashCode() { return Objects.hash(itemName, itemPrice); } }
步骤2:将主商品列表转换为Set集合
Set<MasterItem> masterItemSet = masterList.stream() .map(item -> new MasterItem(item.getItemName(), item.getItemPrice())) .collect(Collectors.toSet());
步骤3:用Stream筛选符合条件的顾客
import java.util.stream.Collectors; List<Customer> qualifyingCustomers = customers.stream() .filter(customer -> { // 提取顾客购物车商品的特征集合 Set<MasterItem> customerItemSet = customer.getCartItems().stream() .map(cartItem -> { // 从itemId拆分出商品名(如"123-XYZ"拆分后取"XYZ") String itemName = cartItem.getItemId().split("-")[1]; return new MasterItem(itemName, cartItem.getItemPrice()); }) .collect(Collectors.toSet()); // 判断顾客是否拥有全部主商品 return customerItemSet.containsAll(masterItemSet); }) .collect(Collectors.toList());
代码说明
- 转主商品为Set:
Set的containsAll操作效率比List高,适合动态变化的主商品列表场景。 - 顾客筛选逻辑:对每个顾客,先把他的购物车商品转换成
MasterItem集合,再通过containsAll判断是否包含所有主商品,符合条件的顾客会被保留。 - itemId拆分:如果存在
itemId格式异常的情况,可以加判断(比如split("-").length == 2)避免数组越界。
可选优化
如果主商品列表或顾客数量较多,建议提前缓存masterItemSet,避免重复转换,提升性能。
内容的提问来源于stack exchange,提问作者Sandy Java
相关产品推荐
相关产品推荐

