中通笔试ShowMeBug编程题复盘
第一题
需求:根据示例数据完成如下功能
1. 统计每个用户的订单数量
2. 统计每个用户消费金额
3. 统计订单数量最多的用户
4. 统计消费金额最多的用户
5. 根据用户id统计该用户的订单
Order类
package com.mmg;public class Order {public String userId;public String orderId;public double amount;public Order(String userId, String orderId, double amount) {this.userId = userId;this.orderId = orderId;this.amount = amount;}public String getUserId() {return userId;}public void setUserId(String userId) {this.userId = userId;}public String getOrderId() {return orderId;}public void setOrderId(String orderId) {this.orderId = orderId;}public double getAmount() {return amount;}public void setAmount(double amount) {this.amount = amount;}@Overridepublic String toString() {return "Order{" +"userId='" + userId + '\'' +", orderId='" + orderId + '\'' +", amount=" + amount +'}';}
}
SimpleTest
package com.mmg;import java.util.*;/*** 需求:* 1. 统计每个用户的订单数量* 2. 统计每个用户消费金额* 3. 统计订单数量最多的用户* 4. 统计消费金额最多的用户* 5. 根据用户id统计该用户的订单*/
public class Test {public static void main(String[] args) {// 示例订单数据List<Order> orders = Arrays.asList(new Order("user1", "order1", 100),new Order("user1", "order2", 200),new Order("user2", "order3", 300),new Order("user3", "order4", 100));// 1. 统计每个用户的订单数量Map<String, Integer> stringIntegerMap = countOrdersByUser(orders);System.out.println(stringIntegerMap);// 2. 统计每个用户消费金额Map<String, Double> stringDoubleMap = sumAmountByUser(orders);System.out.println(stringDoubleMap);// 3. 统计订单数量最多的用户String maxOrderUser = getMaxOrderUser(stringIntegerMap);System.out.println("订单数量最多的用户: " + maxOrderUser);// 4. 统计消费金额最多的用户String maxAmountUser = getMaxAmountUser(stringDoubleMap);System.out.println("消费金额最多的用户: " + maxAmountUser);// 5. 根据用户id统计该用户的订单List<Order> ordersByUserId = getOrdersByUserId(orders, "user1");System.out.println(ordersByUserId);}// 1. 统计每个用户的订单数量public static Map<String, Integer> countOrdersByUser(List<Order> orders) {Map<String, Integer> countMap = new HashMap<>();orders.forEach(order -> {String userId = order.getUserId();countMap.put(userId, countMap.getOrDefault(userId, 0) + 1);});return countMap;}// 2. 统计每个用户消费金额public static Map<String, Double> sumAmountByUser(List<Order> orders) {Map<String, Double> amountMap = new HashMap<>();orders.forEach(order -> {String userId = order.getUserId();double amount = order.getAmount();amountMap.put(userId, amountMap.getOrDefault(userId, 0.00) + amount);});return amountMap;}// 3. 统计订单数量最多的用户public static String getMaxOrderUser(Map<String, Integer> countMap) {String maxUser = null;int maxCount = 0;for (Map.Entry<String, Integer> entry : countMap.entrySet()) {if (entry.getValue() > maxCount) {maxCount = entry.getValue();maxUser = entry.getKey();}}return maxUser;}// 4. 统计消费金额最多的用户public static String getMaxAmountUser(Map<String, Double> amountMap) {String maxUser = null;double maxAmount = 0;for (Map.Entry<String, Double> entry : amountMap.entrySet()) {if (entry.getValue() > maxAmount) {maxAmount = entry.getValue();maxUser = entry.getKey();}}return maxUser;}// 5. 根据用户id统计该用户的订单public static List<Order> getOrdersByUserId(List<Order> orders, String userId) {List<Order> orderList = new ArrayList<>();orders.forEach(order -> {if (userId.equals(order.getUserId())) {orderList.add(order);}});return orderList;}
}
第二题
需求:使用多线程完成以下消费者-生产者案例
package com.mmg;/*** 生产者-消费者案例*/
public class Test02 {public static void main(String[] args) {// 创建容量为10的仓库Test02 warehouse = new Test02(10);// 1. 生产者线程:每次生产3个面包,生产5次Thread producer = new Thread(() -> {try {for (int i = 0; i < 5; i++) {int produceCount = 3;warehouse.produceBread(produceCount);System.out.println("【生产者】生产 " + produceCount + " 个面包,当前库存:" + warehouse.getCurrentStock());Thread.sleep(500); // 模拟生产耗时}} catch (InterruptedException e) {Thread.currentThread().interrupt();System.out.println("生产者线程被中断");}}, "生产者线程");// 2. 消费者线程:每次消费2个面包,消费8次Thread consumer = new Thread(() -> {try {for (int i = 0; i < 8; i++) {int consumeCount = 2;warehouse.consumeBread(consumeCount);System.out.println("【消费者】消费 " + consumeCount + " 个面包,当前库存:" + warehouse.getCurrentStock());Thread.sleep(800); // 模拟消费耗时}} catch (InterruptedException e) {Thread.currentThread().interrupt();System.out.println("消费者线程被中断");}}, "消费者线程");// 启动线程producer.start();consumer.start();}private final int capacity; // 仓库容量(final修饰,初始化后不可变)private int currentStock; // 当前库存(线程共享变量,需同步保护)// 构造方法:初始化仓库容量和初始库存(初始库存为0)public Test02(int capacity) {this.capacity = capacity;this.currentStock = 0;}/*** 生产者方法:生产指定数量的面包* @param count 生产数量(需大于0)* @throws InterruptedException 线程等待被中断时抛出*/public synchronized void produceBread(int count) throws InterruptedException {// 1. 合法性校验:生产数量不能为负数或0if (count <= 0) {throw new IllegalArgumentException("生产数量必须大于0!");}// 2. 等待仓库有足够空间(若当前库存+生产数量 > 容量,需等待)// 用while而非if:防止线程被"虚假唤醒"(唤醒后需重新检查条件)while (currentStock + count > capacity) {System.out.println("【等待生产】当前库存:" + currentStock + ",生产" + count + "个后将超出容量" + capacity + ",等待消费者消费...");this.wait(); // 释放锁,进入等待队列,直到被notifyAll()唤醒}// 3. 执行生产逻辑:更新当前库存currentStock += count;// 4. 唤醒等待的消费者(生产后库存增加,可能有消费者在等库存)this.notifyAll();}/*** 消费者方法:消费指定数量的面包* @param count 消费数量(需大于0)* @throws InterruptedException 线程等待被中断时抛出*/public synchronized void consumeBread(int count) throws InterruptedException {// 1. 合法性校验:消费数量不能为负数或0if (count <= 0) {throw new IllegalArgumentException("消费数量必须大于0!");}// 2. 等待仓库有足够库存(若当前库存 < 消费数量,需等待)while (currentStock < count) {System.out.println("【等待消费】当前库存:" + currentStock + ",不足消费" + count + "个,等待生产者生产...");this.wait(); // 释放锁,进入等待队列,直到被notifyAll()唤醒}// 3. 执行消费逻辑:更新当前库存currentStock -= count;// 4. 唤醒等待的生产者(消费后库存减少,可能有生产者在等空间)this.notifyAll();}// 获取当前库存(同步方法,保证线程读取到最新值)public synchronized int getCurrentStock() {return currentStock;}// 获取仓库剩余空间(同步方法,保证计算基于最新库存)public synchronized int getRemainingSpace() {return capacity - currentStock;}
}