题⽬ 4:订单商品统计:
核⼼考点:
对象聚合(订单包含商品列表)、 MapString, ListOrder>> 、销量 / 营业额 统计、Stream ⾼阶⽤法
题⽬要求: 1. Item (商品):名称、单价、数量 → 提供⼩计⾦额⽅法; 2. Order (订单):订单号、⽤户 ID、商品列表 ListItem> → 提供订单总⾦额⽅法; 3. 按⽤户 ID分组订单(Map:⽤户→订单列表); 4. 统计:每个⽤户总消费、平台总营业额、销量最⾼的商品。
打印结果: =====⽤户消费统计===== ⽤户U002 总消费:3999.00元 ⽤户U001 总消费:7096.00元 平台总营业额:11095.00元 销量最⾼商品:⼿机,总销量:2
思路分析:
一、Item 类 (商品)
class Item { private String name; // 商品名:手机、电脑 private double price; // 单价 private int count; // 购买数量 // 小计金额 = 单价 × 数量(题目要求必须提供的方法) public double getSubtotal() { return price * count; } // 构造方法:创建商品时传入 名称、单价、数量 public Item(String name, double price, int count) { this.name = name; this.price = price; this.count = count; } // getter:外部要读取商品信息必须用get public String getName() { return name; } public int getCount() { return count; } }核心思路
- tem 是基础数据单元,只负责自己的单价、数量、小计。
getSubtotal()是题目强制要求:单个商品的总价。- 提供 getter,让外部类(Order)能读取商品名称、数量。
二、Order 类(订单)
class Order { private String orderId; // 订单编号 O001 private String userId; // 用户编号 U001 private List<Item> itemList; // 一个订单包含多个商品 → 对象聚合! // 订单总金额 = 所有商品的小计加起来(题目要求) public double getTotalAmount() { return itemList.stream() .mapToDouble(Item::getSubtotal) // 把每个商品转成小计金额 .sum(); // 求和 } // 构造方法:创建订单时传入 订单号、用户ID、商品列表 public Order(String orderId, String userId, List<Item> itemList) { this.orderId = orderId; this.userId = userId; this.itemList = itemList; } // getter public String getUserId() { return userId; } public List<Item> getItemList() { return itemList; } }核心思路
对象聚合(核心考点)
一个订单 包含 多个商品
代码体现:List<Item> itemList
getTotalAmount() 订单总金额
流处理商品列表
mapToDouble(Item::getSubtotal):把每个商品 → 金额
sum():把所有金额加起来 = 订单总价
三、主程序:完整执行流程(最关键)
第 1 步:构造测试数据
// 商品 Item phone = new Item("手机", 1999, 1); Item phone2 = new Item("手机", 1999, 1); Item computer = new Item("电脑", 5099, 1); Item earphone = new Item("耳机", 1999, 1); // 订单 Order o1 = new Order("O001", "U001", Arrays.asList(phone, computer)); Order o2 = new Order("O002", "U001", Arrays.asList(earphone)); Order o3 = new Order("O003", "U002", Arrays.asList(phone2)); // 所有订单放到一个集合里 List<Order> orderList = Arrays.asList(o1, o2, o3);思路
- 先造商品
- 再造订单,订单里装入商品
- 最后把所有订单放到
orderList,方便统一处理
第 2 步:按用户 ID 分组订单(Map<String, List<Order>>)
Map<String, List<Order>> userOrderMap = orderList.stream() .collect(Collectors.groupingBy(Order::getUserId));思路(Stream 分组核心)
groupingBy(Order::getUserId)- 按照userId分组
- key = 用户 ID
- value = 这个用户的所有订单列表
第 3 步:统计每个用户总消费
userOrderMap.forEach((userId, orders) -> { double total = orders.stream() .mapToDouble(Order::getTotalAmount) // 每个订单 → 金额 .sum(); // 求和 = 该用户总消费 System.out.printf("用户%s 总消费:%.2f元%n", userId, total); });思路
- 遍历每个用户
- 把该用户的所有订单金额加起来
- 输出格式化结果
第 4 步:统计平台总营业额
double platformTotal = orderList.stream() .mapToDouble(Order::getTotalAmount) .sum(); System.out.printf("平台总营业额:%.2f元%n", platformTotal);思路
- 把所有订单的金额加起来
- 就是平台总营业额
- 最简单的统计
第 5 步:统计销量最高的商品(最难!Stream 高阶)
第一步:把所有订单里的商品全部展开
orderList.stream() .flatMap(order -> order.getItemList().stream())思路
flatMap= 扁平化- 把:
订单1[商品1,商品2]、订单2[商品3]变成:[商品1,商品2,商品3]
第二步:按商品名统计总销量
.collect(Collectors.groupingBy( Item::getName, // 按商品名分组 Collectors.summingInt(Item::getCount) // 每组数量求和 ));得到一个 Map:
- 手机 → 2
- 电脑 → 1
- 耳机 → 1
第三步:找出销量最大的那个
Map.Entry<String, Integer> topItem = itemSalesMap.entrySet().stream() .max(Map.Entry.comparingByValue()) // 按销量值比较,取最大 .orElse(null);思路
- 比较 Map 里的 value(销量)
- 取出最大的那一组
- 最后打印商品名 + 销量
