You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Java 8 Stream API改写遍历Map并嵌套迭代List的循环

Rewriting Shopping Basket Price Calculation with Java 8 Streams

Got it, let's break down how to convert your nested loop logic into clean Java 8 Stream code, while preserving the core behavior: each promotion is applied exactly once to its target product, and we calculate the total basket price with discounts where applicable.

First, Let's Recap the Original Logic

Your current code does:

  • Iterate over each product-quantity entry in the basket
  • For each entry, loop through the promotions list to find one that matches the product
  • If a match is found: use promotion.computeDiscountedPrice() to calculate the line item cost, then remove the promotion from the list (so it can't be reused)
  • If no match: calculate the line item cost at full price
  • Sum all line item costs for the total

Key Challenges for Stream Rewrite

Streams work best with stateless operations, but we need to track which promotions have been used (since each can only be applied once). To handle this, we'll first organize promotions into a structured collection that lets us safely consume them as we process the basket.

Solution Code

Let's assume you have these classes (adjust method names to match your actual code):

class Product {
    private String id; // or unique identifier of your choice
    private double price;

    // Getters, and ensure equals()/hashCode() are implemented based on the unique identifier
}

class Promotion {
    private Product applicableProduct;

    public Product getApplicableProduct() {
        return applicableProduct;
    }

    public double computeDiscountedPrice(Product product, int quantity) {
        // Replace with your actual discount calculation logic
        return product.getPrice() * quantity * 0.8; // Example: 20% off
    }
}

Step 1: Organize Promotions by Target Product

First, we'll group promotions into a map where each key is a Product, and the value is a queue of promotions applicable to that product. Using a queue ensures we use promotions in the order they appeared in the original list (matching your loop's behavior of using the first matching promotion):

// Group promotions by their target product, preserving order with a LinkedList queue
Map<Product, Queue<Promotion>> promotionQueueMap = originalPromotions.stream()
    .collect(Collectors.groupingBy(
        Promotion::getApplicableProduct,
        Collectors.toCollection(LinkedList::new)
    ));

Step 2: Calculate Total with Streams

Now we can process the basket entries with Streams, consuming promotions from the queue as we go:

double total = basket.entrySet().stream()
    .mapToDouble(entry -> {
        Product product = entry.getKey();
        int quantity = entry.getValue();
        
        // Check if there's an unused promotion for this product
        Queue<Promotion> productPromotions = promotionQueueMap.get(product);
        if (productPromotions != null && !productPromotions.isEmpty()) {
            // Use the first available promotion and remove it from the queue
            Promotion appliedPromotion = productPromotions.poll();
            return appliedPromotion.computeDiscountedPrice(product, quantity);
        } else {
            // No promotion available: calculate full price
            return product.getPrice() * quantity;
        }
    })
    .sum();

Why This Works

  • Preserves Original Behavior: The queue ensures we use promotions in the order they were provided, just like your nested loop. Each promotion is removed from the queue after use, so it can't be applied again.
  • Cleaner Code: Replaces nested loops with a declarative Stream pipeline that's easier to read and maintain.
  • Controlled State: The only state we track is the queue of unused promotions, which is modified in a predictable way. For single-threaded environments (typical for basket calculations), this is safe. If you need thread safety, swap LinkedList with ConcurrentLinkedQueue and HashMap with ConcurrentHashMap.

Notes

  • Ensure your Product class has properly implemented equals() and hashCode() so the map grouping works correctly.
  • If a product has multiple applicable promotions, this code will use them one per basket entry (though if your basket uses a HashMap, each product will only appear once, so each product uses at most one promotion—matching your original logic).

内容的提问来源于stack exchange,提问作者josephine preethi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 09:13:53