Skip to content
章节导航

Collectors.summingInt() 是用于计算整数类型元素总和的收集器,返回 Integer 类型的求和结果。

java
// 1. 基本用法 - 计算整数列表的总和
 List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
 
 Integer sum = numbers.stream()
     .collect(Collectors.summingInt(n -> n));
 
 System.out.println("Sum: " + sum); // 15
 
 // 2. 方法引用简化写法
 Integer sum2 = numbers.stream()
     .collect(Collectors.summingInt(Integer::intValue));
 
 // 3. 从 IntStream 直接使用
 int intStreamSum = IntStream.of(1, 2, 3, 4, 5).sum();
 System.out.println("IntStream sum: " + intStreamSum); // 15

核心特性

1. 自动空流处理

javascript
// 空流返回 0
Integer
emptySum = Stream.
<Integer>empty()
    .collect(Collectors.summingInt(n -> n));

    System.out.println("Empty stream sum: " + emptySum); // 0

    // 包含 null 值的流
    List
    <Integer>withNulls = Arrays.asList(1, null, 3, null, 5);

        // 过滤 null 值
        Integer sumWithoutNulls = withNulls.stream()
        .filter(Objects::nonNull)
        .collect(Collectors.summingInt(n -> n));

        System.out.println("Sum without nulls: " + sumWithoutNulls); // 9

        // 使用默认值处理 null
        Integer sumWithDefault = withNulls.stream()
        .collect(Collectors.summingInt(n -> n != null ? n : 0));

        System.out.println("Sum with default 0: " + sumWithDefault); // 9

2. 处理大数(溢出检查)

java
// summingInt 内部使用 long 累加,最后转换为 int
        // 所以可以处理较大的 int 值,但最终结果不能超过 Integer 范围
        
        List<Integer> largeNumbers = Arrays.asList(
            Integer.MAX_VALUE - 100,
            Integer.MAX_VALUE - 200,
            300  // 这个加法会导致溢出
        );
        
        // summingInt 会检查溢出
        try {
            Integer overflowSum = largeNumbers.stream()
                .collect(Collectors.summingInt(n -> n));
            System.out.println("Sum: " + overflowSum);
        } catch (ArithmeticException e) {
            System.out.println("Overflow detected: " + e.getMessage());
        }
        
        // 使用 long 类型避免溢出
        Long longSum = largeNumbers.stream()
            .collect(Collectors.summingLong(Integer::longValue));
        
        System.out.println("Long sum: " + longSum);
        
        // 或者使用 reduce
        Optional<Integer> reducedSum = largeNumbers.stream()
            .reduce(Integer::sum);
        
        System.out.println("Reduced sum: " + reducedSum.orElse(0));

实际应用示例

示例 1:订单金额统计

java
class OrderItem {
    private String productName;
    private int quantity;
    private int unitPrice;  // 单位为分,避免浮点数
    
    public OrderItem(String productName, int quantity, int unitPrice) {
        this.productName = productName;
        this.quantity = quantity;
        this.unitPrice = unitPrice;
    }
    
    // 计算总价
    public int getTotalPrice() {
        return quantity * unitPrice;
    }
    
    // getters
    public String getProductName() { return productName; }
    public int getQuantity() { return quantity; }
    public int getUnitPrice() { return unitPrice; }
}

public class OrderAnalysis {
    public static void main(String[] args) {
        List<OrderItem> items = Arrays.asList(
            new OrderItem("Laptop", 1, 8000000),    // 80000.00元
            new OrderItem("Mouse", 2, 2500),        // 25.00元
            new OrderItem("Keyboard", 1, 3500),     // 35.00元
            new OrderItem("Monitor", 1, 2000000),   // 20000.00元
            new OrderItem("USB Cable", 3, 1500)     // 15.00元
        );
        
        // 1. 计算订单总金额
        Integer totalAmount = items.stream()
            .collect(Collectors.summingInt(OrderItem::getTotalPrice));
        
        System.out.println("订单总金额: " + formatCurrency(totalAmount));
        // 订单总金额: ¥100,075.00
        
        // 2. 计算平均单价
        Double averagePrice = items.stream()
            .collect(Collectors.averagingInt(OrderItem::getUnitPrice));
        
        System.out.println("平均单价: " + formatCurrency(averagePrice.intValue()));
        
        // 3. 按价格区间统计
        Map<String, Integer> sumByPriceRange = items.stream()
            .collect(Collectors.groupingBy(
                item -> {
                    int price = item.getUnitPrice();
                    if (price < 5000) return "低价 (<50元)";
                    else if (price < 50000) return "中价 (50-500元)";
                    else return "高价 (>500元)";
                },
                Collectors.summingInt(OrderItem::getTotalPrice)
            ));
        
        System.out.println("\n按价格区间统计:");
        sumByPriceRange.forEach((range, sum) -> 
            System.out.printf("%s: %s%n", range, formatCurrency(sum)));
        
        // 4. 统计总商品数量
        Integer totalQuantity = items.stream()
            .collect(Collectors.summingInt(OrderItem::getQuantity));
        
        System.out.println("\n总商品数量: " + totalQuantity + "");
    }
    
    private static String formatCurrency(int amount) {
        // 将分转换为元并格式化
        double yuan = amount / 100.0;
        return String.format("¥%,.2f", yuan);
    }
}

示例 2:员工薪资统计

java
class Employee {
    private String name;
    private String department;
    private int salary;  // 月薪,单位元
    private int bonus;   // 奖金
    private int yearsOfService;
    
    public Employee(String name, String department, int salary, 
                    int bonus, int yearsOfService) {
        this.name = name;
        this.department = department;
        this.salary = salary;
        this.bonus = bonus;
        this.yearsOfService = yearsOfService;
    }
    
    // 计算总薪资(月薪+奖金)
    public int getTotalCompensation() {
        return salary + bonus;
    }
    
    // 计算年薪
    public int getAnnualSalary() {
        return salary * 12 + bonus;
    }
    
    // getters
    public String getName() { return name; }
    public String getDepartment() { return department; }
    public int getSalary() { return salary; }
    public int getBonus() { return bonus; }
    public int getYearsOfService() { return yearsOfService; }
}

public class SalaryAnalysis {
    public static void main(String[] args) {
        List<Employee> employees = Arrays.asList(
            new Employee("Alice", "Engineering", 15000, 30000, 3),
            new Employee("Bob", "Engineering", 18000, 25000, 5),
            new Employee("Charlie", "Sales", 12000, 50000, 2),
            new Employee("Diana", "Sales", 14000, 45000, 4),
            new Employee("Eve", "HR", 10000, 15000, 1),
            new Employee("Frank", "Engineering", 20000, 40000, 8),
            new Employee("Grace", "Marketing", 13000, 20000, 3)
        );
        
        // 1. 按部门统计月薪总和
        Map<String, Integer> salarySumByDept = employees.stream()
            .collect(Collectors.groupingBy(
                Employee::getDepartment,
                Collectors.summingInt(Employee::getSalary)
            ));
        
        System.out.println("各部门月薪总和:");
        salarySumByDept.forEach((dept, sum) -> 
            System.out.printf("%s: ¥%,d%n", dept, sum));
        
        // 2. 按部门统计总薪资(月薪+奖金)
        Map<String, Integer> totalCompByDept = employees.stream()
            .collect(Collectors.groupingBy(
                Employee::getDepartment,
                Collectors.summingInt(Employee::getTotalCompensation)
            ));
        
        System.out.println("\n各部门总薪资(月薪+奖金):");
        totalCompByDept.forEach((dept, sum) -> 
            System.out.printf("%s: ¥%,d%n", dept, sum));
        
        // 3. 按部门统计年薪总和
        Map<String, Integer> annualSalaryByDept = employees.stream()
            .collect(Collectors.groupingBy(
                Employee::getDepartment,
                Collectors.summingInt(Employee::getAnnualSalary)
            ));
        
        System.out.println("\n各部门年薪总和:");
        annualSalaryByDept.forEach((dept, sum) -> 
            System.out.printf("%s: ¥%,d%n", dept, sum));
        
        // 4. 按工作年限分组统计
        Map<String, Integer> salaryByExperience = employees.stream()
            .collect(Collectors.groupingBy(
                emp -> {
                    if (emp.getYearsOfService() < 2) return "初级 (<2年)";
                    else if (emp.getYearsOfService() < 5) return "中级 (2-5年)";
                    else return "高级 (>5年)";
                },
                Collectors.summingInt(Employee::getSalary)
            ));
        
        System.out.println("\n按工作年限统计月薪总和:");
        salaryByExperience.forEach((exp, sum) -> 
            System.out.printf("%s: ¥%,d%n", exp, sum));
        
        // 5. 统计全公司总支出
        Integer totalMonthlySalary = employees.stream()
            .collect(Collectors.summingInt(Employee::getSalary));
        
        Integer totalBonus = employees.stream()
            .collect(Collectors.summingInt(Employee::getBonus));
        
        Integer totalAnnualExpense = employees.stream()
            .collect(Collectors.summingInt(Employee::getAnnualSalary));
        
        System.out.println("\n公司薪资总览:");
        System.out.printf("月薪总和: ¥%,d%n", totalMonthlySalary);
        System.out.printf("奖金总和: ¥%,d%n", totalBonus);
        System.out.printf("年薪总和: ¥%,d%n", totalAnnualExpense);
        System.out.printf("平均月薪: ¥%,.0f%n", 
            employees.stream().collect(Collectors.averagingInt(Employee::getSalary)));
        
        // 6. 复杂统计:各部门的详细薪资报告
        Map<String, Map<String, Object>> deptSalaryReport = employees.stream()
            .collect(Collectors.groupingBy(
                Employee::getDepartment,
                Collectors.collectingAndThen(
                    Collectors.toList(),
                    list -> {
                        int deptSize = list.size();
                        int salarySum = list.stream()
                            .collect(Collectors.summingInt(Employee::getSalary));
                        int bonusSum = list.stream()
                            .collect(Collectors.summingInt(Employee::getBonus));
                        double avgSalary = list.stream()
                            .collect(Collectors.averagingInt(Employee::getSalary));
                        
                        return Map.of(
                            "员工数", deptSize,
                            "月薪总和", salarySum,
                            "奖金总和", bonusSum,
                            "平均月薪", String.format("¥%,.0f", avgSalary),
                            "人均总薪资", String.format("¥%,.0f", 
                                (double)(salarySum + bonusSum) / deptSize)
                        );
                    }
                )
            ));
        
        System.out.println("\n各部门详细薪资报告:");
        deptSalaryReport.forEach((dept, report) -> {
            System.out.println("\n" + dept + "部门:");
            report.forEach((key, value) -> 
                System.out.printf("  %s: %s%n", key, value));
        });
    }
}

示例 3:库存管理系统

java
class InventoryItem {
    private String productId;
    private String productName;
    private String category;
    private int unitPrice;      // 单价(分)
    private int stockQuantity;  // 库存数量
    private int reorderLevel;   // 再订货点
    
    public InventoryItem(String productId, String productName, String category,
                        int unitPrice, int stockQuantity, int reorderLevel) {
        this.productId = productId;
        this.productName = productName;
        this.category = category;
        this.unitPrice = unitPrice;
        this.stockQuantity = stockQuantity;
        this.reorderLevel = reorderLevel;
    }
    
    // 计算库存价值
    public int getInventoryValue() {
        return unitPrice * stockQuantity;
    }
    
    // 是否需要补货
    public boolean needsReorder() {
        return stockQuantity <= reorderLevel;
    }
    
    // getters
    public String getProductId() { return productId; }
    public String getProductName() { return productName; }
    public String getCategory() { return category; }
    public int getUnitPrice() { return unitPrice; }
    public int getStockQuantity() { return stockQuantity; }
    public int getReorderLevel() { return reorderLevel; }
}

public class InventoryManagement {
    public static void main(String[] args) {
        List<InventoryItem> inventory = Arrays.asList(
            new InventoryItem("P001", "Laptop", "Electronics", 8000000, 50, 10),
            new InventoryItem("P002", "Mouse", "Electronics", 2500, 200, 50),
            new InventoryItem("P003", "Notebook", "Stationery", 1500, 300, 100),
            new InventoryItem("P004", "Pen", "Stationery", 500, 1000, 200),
            new InventoryItem("P005", "Monitor", "Electronics", 2000000, 30, 5),
            new InventoryItem("P006", "USB Cable", "Accessories", 1500, 150, 30),
            new InventoryItem("P007", "Keyboard", "Electronics", 3500, 80, 20),
            new InventoryItem("P008", "Paper", "Stationery", 2000, 500, 100),
            new InventoryItem("P009", "Headphones", "Accessories", 15000, 40, 10)
        );
        
        // 1. 按类别统计库存价值
        Map<String, Integer> valueByCategory = inventory.stream()
            .collect(Collectors.groupingBy(
                InventoryItem::getCategory,
                Collectors.summingInt(InventoryItem::getInventoryValue)
            ));
        
        System.out.println("按类别统计库存价值:");
        valueByCategory.forEach((category, value) -> 
            System.out.printf("%s: %s%n", category, formatCurrency(value)));
        
        // 2. 按类别统计库存总量
        Map<String, Integer> quantityByCategory = inventory.stream()
            .collect(Collectors.groupingBy(
                InventoryItem::getCategory,
                Collectors.summingInt(InventoryItem::getStockQuantity)
            ));
        
        System.out.println("\n按类别统计库存数量:");
        quantityByCategory.forEach((category, quantity) -> 
            System.out.printf("%s: %,d 件%n", category, quantity));
        
        // 3. 统计需要补货的商品总价值
        Integer reorderValue = inventory.stream()
            .filter(InventoryItem::needsReorder)
            .collect(Collectors.summingInt(InventoryItem::getInventoryValue));
        
        System.out.println("\n需要补货的商品总价值: " + formatCurrency(reorderValue));
        
        // 按类别统计需要补货的数量
        Map<String, Integer> reorderQuantityByCategory = inventory.stream()
            .filter(InventoryItem::needsReorder)
            .collect(Collectors.groupingBy(
                InventoryItem::getCategory,
                Collectors.summingInt(InventoryItem::getStockQuantity)
            ));
        
        System.out.println("需要补货的商品数量(按类别):");
        reorderQuantityByCategory.forEach((category, quantity) -> 
            System.out.printf("  %s: %,d 件%n", category, quantity));
        
        // 4. 统计总库存价值
        Integer totalInventoryValue = inventory.stream()
            .collect(Collectors.summingInt(InventoryItem::getInventoryValue));
        
        System.out.println("\n总库存价值: " + formatCurrency(totalInventoryValue));
        
        // 5. 统计高价商品(单价>100元)的总价值
        Integer highValueItems = inventory.stream()
            .filter(item -> item.getUnitPrice() > 10000)  // >100元
            .collect(Collectors.summingInt(InventoryItem::getInventoryValue));
        
        System.out.println("高价商品总价值: " + formatCurrency(highValueItems));
        
        // 6. 库存周转分析
        Map<String, Map<String, Integer>> turnoverAnalysis = inventory.stream()
            .collect(Collectors.groupingBy(
                InventoryItem::getCategory,
                Collectors.collectingAndThen(
                    Collectors.toList(),
                    list -> {
                        int totalValue = list.stream()
                            .collect(Collectors.summingInt(InventoryItem::getInventoryValue));
                        int totalQuantity = list.stream()
                            .collect(Collectors.summingInt(InventoryItem::getStockQuantity));
                        int lowStockCount = (int) list.stream()
                            .filter(InventoryItem::needsReorder)
                            .count();
                        
                        return Map.of(
                            "总价值", totalValue,
                            "总数量", totalQuantity,
                            "缺货商品数", lowStockCount,
                            "平均单价", totalValue / Math.max(totalQuantity, 1)
                        );
                    }
                )
            ));
        
        System.out.println("\n库存周转分析:");
        turnoverAnalysis.forEach((category, stats) -> {
            System.out.println("\n" + category + ":");
            stats.forEach((key, value) -> {
                if (key.equals("总价值")) {
                    System.out.printf("  %s: %s%n", key, formatCurrency(value));
                } else {
                    System.out.printf("  %s: %,d%n", key, value);
                }
            });
        });
        
        // 7. 生成采购建议报告
        String purchaseReport = inventory.stream()
            .filter(InventoryItem::needsReorder)
            .sorted(Comparator.comparingInt(InventoryItem::getInventoryValue).reversed())
            .map(item -> String.format(
                "商品: %s (ID: %s), 当前库存: %d, 建议采购: %d, 预估价值: %s",
                item.getProductName(),
                item.getProductId(),
                item.getStockQuantity(),
                item.getReorderLevel() * 3,  // 建议采购量为再订货点的3倍
                formatCurrency(item.getUnitPrice() * item.getReorderLevel() * 3)
            ))
            .collect(Collectors.joining("\n", "采购建议报告:\n===============\n", "\n==============="));
        
        System.out.println("\n" + purchaseReport);
    }
    
    private static String formatCurrency(int amount) {
        double yuan = amount / 100.0;
        return String.format("¥%,.2f", yuan);
    }
}