如何在Java 8中基于商品类别和总数量计算折扣?
问题修正:按类别总数量计算折扣的购物车总价方法
数据集
name: tea, pricePerUnit: 5.3, quantity: 2, category: drinks name: coffee, pricePerUnit: 3.5, quantity: 2, category: drinks name: cheese, pricePerUnit: 8, quantity: 2, category: food
折扣规则
同一类别下商品总购买数量超过3件,该类别下所有商品均享受10%折扣。
存在Bug的原代码
public BigDecimal calculateTotalWithDiscountAndCategory(ShoppingCart shoppingCart){ return shoppingCart.getProducts() .stream() .collect(Collectors.groupingBy(Product::getCategory)) .entrySet() .stream() .map( v -> v.getValue() .stream() .map(product ->{ if(product.getQuantity() > 3){ BigDecimal currentTotal = product.getPricePerUnit().multiply(BigDecimal.valueOf(product.getQuantity())); return currentTotal.multiply(BigDecimal.valueOf(0.9)); }else { return product.getPricePerUnit().multiply(BigDecimal.valueOf(product.getQuantity())); } } ) .reduce(BigDecimal::add) .orElse(BigDecimal.ZERO) ).reduce(BigDecimal::add) .orElse(BigDecimal.ZERO); }
Bug分析
原代码错误地判断单个商品的购买数量是否超过3,但规则要求的是整个类别下的总数量超过3才给该类别所有商品打折扣。比如示例中drinks类别总数量是4,符合折扣条件,但原代码因为单个商品数量都是2,所以没触发折扣。
修改后的代码
public BigDecimal calculateTotalWithDiscountAndCategory(ShoppingCart shoppingCart) { return shoppingCart.getProducts() .stream() .collect(Collectors.groupingBy(Product::getCategory)) .entrySet() .stream() .map(entry -> { // 计算当前类别下的总购买数量 int totalCategoryQuantity = entry.getValue() .stream() .mapToInt(Product::getQuantity) .sum(); // 判断是否满足折扣条件 boolean needDiscount = totalCategoryQuantity > 3; // 计算该类别下所有商品的总价,按需应用折扣 return entry.getValue() .stream() .map(product -> { BigDecimal itemTotal = product.getPricePerUnit() .multiply(BigDecimal.valueOf(product.getQuantity())); return needDiscount ? itemTotal.multiply(BigDecimal.valueOf(0.9)) : itemTotal; }) .reduce(BigDecimal::add) .orElse(BigDecimal.ZERO); }) .reduce(BigDecimal::add) .orElse(BigDecimal.ZERO); }
修改说明
- 先统计每个类别下的总购买数量,而非单个商品的数量
- 根据类别总数量判断是否触发折扣规则
- 若满足折扣条件,该类别下所有商品的总价统一乘以0.9,否则按原价计算
- 最后汇总所有类别的计算结果得到最终总价
内容的提问来源于stack exchange,提问作者D.Anush
相关产品推荐
相关产品推荐

