Skip to content
章节导航

Collectors.summingDouble() 是用于计算双精度浮点数总和的收集器,返回 Double 类型的求和结果。

基本用法

java
// 1. 基本用法 - 计算Double列表的总和
 List<Double> prices = Arrays.asList(19.99, 29.99, 39.99, 49.99);
 
 Double total = prices.stream()
     .collect(Collectors.summingDouble(n -> n));
 
 System.out.println("Total price: " + total); // 139.96
 System.out.printf("Formatted: %.2f%n", total); // 139.96
 
 // 2. 方法引用简化写法
 Double total2 = prices.stream()
     .collect(Collectors.summingDouble(Double::doubleValue));
 
 // 3. 从DoubleStream直接使用
 double doubleStreamSum = DoubleStream.of(19.99, 29.99, 39.99, 49.99)
     .sum();
 System.out.println("DoubleStream sum: " + doubleStreamSum); // 139.96

核心特性

1. 浮点数精度处理

java
public class PrecisionHandling {
    public static void main(String[] args) {
        // 浮点数相加可能有精度问题
        List<Double> values = Arrays.asList(0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1);
        
        Double sum = values.stream()
            .collect(Collectors.summingDouble(n -> n));
        
        System.out.println("Sum of ten 0.1s: " + sum); // 理论上应该是1.0
        System.out.println("Is exactly 1.0? " + (sum == 1.0)); // 可能为false
        System.out.printf("Formatted: %.15f%n", sum); // 查看实际值
        
        // 对于精确计算,使用BigDecimal
        BigDecimal exactSum = values.stream()
            .map(BigDecimal::valueOf)
            .reduce(BigDecimal.ZERO, BigDecimal::add);
        
        System.out.println("Exact sum (BigDecimal): " + exactSum); // 1.0
        
        // Kahan求和算法减少误差
        double[] numbers = {0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1};
        double kahanSum = kahanSum(numbers);
        System.out.println("Kahan sum: " + kahanSum); // 更接近1.0
    }
    
    // Kahan求和算法实现
    private static double kahanSum(double[] numbers) {
        double sum = 0.0;
        double c = 0.0; // 补偿误差
        
        for (double num : numbers) {
            double y = num - c;
            double t = sum + y;
            c = (t - sum) - y;
            sum = t;
        }
        return sum;
    }
}

2. 特殊值处理

java
public class SpecialValueHandling {
    public static void main(String[] args) {
        // 处理特殊浮点数值
        List<Double> specialValues = Arrays.asList(
            1.5,
            Double.POSITIVE_INFINITY,
            2.5,
            Double.NaN,
            3.5,
            Double.NEGATIVE_INFINITY
        );
        
        // ❌ 包含特殊值会导致异常或错误结果
        try {
            Double badSum = specialValues.stream()
                .collect(Collectors.summingDouble(n -> n));
            System.out.println("Bad sum: " + badSum);
        } catch (Exception e) {
            System.out.println("Exception: " + e.getMessage());
        }
        
        // ✅ 过滤特殊值
        Double filteredSum = specialValues.stream()
            .filter(n -> Double.isFinite(n)) // 过滤无穷大和NaN
            .collect(Collectors.summingDouble(n -> n));
        
        System.out.println("Filtered sum: " + filteredSum); // 7.5 (1.5+2.5+3.5)
        
        // ✅ 处理无穷大
        Double sumWithInfinity = specialValues.stream()
            .map(n -> {
                if (Double.isInfinite(n)) {
                    return n == Double.POSITIVE_INFINITY ? 1e10 : -1e10;
                } else if (Double.isNaN(n)) {
                    return 0.0;
                }
                return n;
            })
            .collect(Collectors.summingDouble(n -> n));
        
        System.out.println("Processed sum: " + sumWithInfinity);
        
        // 检查结果是否有效
        Double result = filteredSum;
        if (Double.isNaN(result)) {
            System.out.println("Result is NaN!");
        } else if (Double.isInfinite(result)) {
            System.out.println("Result is infinite!");
        } else {
            System.out.println("Result is finite: " + result);
        }
    }
}