Skip to content
章节导航

Collectors.averagingLong()

Collectors.averagingLong() 是专门用于计算长整型(long)数据平均值的收集器,返回结果为 Double 类型。

基本用法

java
// 1. 基本用法 - 计算 Long 列表的平均值
List<Long> numbers = Arrays.asList(100L, 200L, 300L, 400L, 500L);
Double average = numbers.stream()
        .collect(Collectors.averagingLong(n -> n));
System.out.println("Average: " + average); // 300.0

// 2. 方法引用简化写法
Double average2 = numbers.stream()
        .collect(Collectors.averagingLong(Long::longValue));

// 3. 从 LongStream 直接使用
double longStreamAverage = LongStream.of(100L, 200L, 300L, 400L, 500L)
        .average()
        .orElse(0.0);
System.out.println("LongStream average: " + longStreamAverage); // 300.0

// 4. 处理大数据(避免溢出)
List<Long> largeNumbers = Arrays.asList(
        Long.MAX_VALUE - 1000L,
        Long.MAX_VALUE - 2000L,
        Long.MAX_VALUE - 3000L
);
Double largeAverage = largeNumbers.stream()
        .collect(Collectors.averagingLong(n -> n));
System.out.println("Average of large numbers: " + largeAverage);

核心特性

1. 处理大数无溢出

java
// 使用 averagingLong 可以安全处理大数相加
        List<Long> veryLargeNumbers = Arrays.asList(
                Long.MAX_VALUE,
                Long.MAX_VALUE - 1000L,
                Long.MAX_VALUE - 2000L
        );

        // 内部使用双精度浮点数计算,不会溢出
        Double average = veryLargeNumbers.stream()
                .collect(Collectors.averagingLong(n -> n));

        System.out.println("Average of very large numbers: " + average);

        // 对比:手动相加可能溢出
        try {
            long manualSum = veryLargeNumbers.stream().reduce(0L, Long::sum);
            System.out.println("Manual sum (may overflow): " + manualSum);
        } catch (ArithmeticException e) {
            System.out.println("Manual sum overflowed!");
        }

2. 空流和 null 值处理

java
// 空流返回 0.0
        Double emptyAverage = Stream.<Long>empty()
            .collect(Collectors.averagingLong(n -> n));
        
        System.out.println("Empty stream average: " + emptyAverage); // 0.0
        
        // 包含 null 值的流
        List<Long> withNulls = Arrays.asList(100L, null, 300L, null, 500L);
        
        Double average = withNulls.stream()
            .filter(Objects::nonNull)
            .collect(Collectors.averagingLong(n -> n));
        
        System.out.println("Average with nulls filtered: " + average); // 300.0
        
        // 提供默认值
        Double averageWithDefault = withNulls.stream()
            .collect(Collectors.averagingLong(n -> n != null ? n : 0L));
        
        System.out.println("Average with default 0: " + averageWithDefault); // 180.0

实际应用示例

示例 1:时间统计

java
class ApiRequest {
    private String endpoint;
    private long responseTime; // 毫秒
    private long requestSize;  // 字节
    private LocalDateTime timestamp;
    
    public ApiRequest(String endpoint, long responseTime, long requestSize) {
        this.endpoint = endpoint;
        this.responseTime = responseTime;
        this.requestSize = requestSize;
        this.timestamp = LocalDateTime.now();
    }
    
    // getters
    public String getEndpoint() { return endpoint; }
    public long getResponseTime() { return responseTime; }
    public long getRequestSize() { return requestSize; }
    public LocalDateTime getTimestamp() { return timestamp; }
}

public class ApiPerformanceAnalysis {
    public static void main(String[] args) {
        List<ApiRequest> requests = Arrays.asList(
            new ApiRequest("/api/users", 150L, 2048L),
            new ApiRequest("/api/users", 200L, 4096L),
            new ApiRequest("/api/products", 80L, 1024L),
            new ApiRequest("/api/products", 120L, 3072L),
            new ApiRequest("/api/orders", 500L, 8192L),
            new ApiRequest("/api/orders", 450L, 6144L),
            new ApiRequest("/api/users", 180L, 3072L)
        );
        
        // 1. 按端点统计平均响应时间
        Map<String, Double> avgResponseTimeByEndpoint = requests.stream()
            .collect(Collectors.groupingBy(
                ApiRequest::getEndpoint,
                Collectors.averagingLong(ApiRequest::getResponseTime)
            ));
        
        System.out.println("Average response time by endpoint (ms):");
        avgResponseTimeByEndpoint.forEach((endpoint, avgTime) -> 
            System.out.printf("%s: %.2f ms%n", endpoint, avgTime));
        // /api/users: 176.67 ms
        // /api/products: 100.00 ms
        // /api/orders: 475.00 ms
        
        // 2. 按端点统计平均请求大小
        Map<String, Double> avgSizeByEndpoint = requests.stream()
            .collect(Collectors.groupingBy(
                ApiRequest::getEndpoint,
                Collectors.averagingLong(ApiRequest::getRequestSize)
            ));
        
        System.out.println("\nAverage request size by endpoint (bytes):");
        avgSizeByEndpoint.forEach((endpoint, avgSize) -> 
            System.out.printf("%s: %.2f bytes%n", endpoint, avgSize));
        
        // 3. 按小时统计平均响应时间
        Map<Integer, Double> avgResponseTimeByHour = requests.stream()
            .collect(Collectors.groupingBy(
                req -> req.getTimestamp().getHour(),
                Collectors.averagingLong(ApiRequest::getResponseTime)
            ));
        
        System.out.println("\nAverage response time by hour:");
        avgResponseTimeByHour.entrySet().stream()
            .sorted(Map.Entry.comparingByKey())
            .forEach(entry -> 
                System.out.printf("%02d:00: %.2f ms%n", entry.getKey(), entry.getValue()));
    }
}

示例 2:金融数据分析

java
class Transaction {
    private String accountId;
    private long amount;  // 以分为单位(避免浮点数精度问题)
    private String type;  // "DEPOSIT", "WITHDRAWAL", "TRANSFER"
    private LocalDateTime timestamp;
    private String category;
    
    public Transaction(String accountId, long amount, String type, String category) {
        this.accountId = accountId;
        this.amount = amount;
        this.type = type;
        this.category = category;
        this.timestamp = LocalDateTime.now();
    }
    
    // getters
    public String getAccountId() { return accountId; }
    public long getAmount() { return amount; }
    public String getType() { return type; }
    public String getCategory() { return category; }
    public LocalDateTime getTimestamp() { return timestamp; }
    
    // 转换为元
    public double getAmountInYuan() {
        return amount / 100.0;
    }
}

public class FinancialAnalysis {
    public static void main(String[] args) {
        List<Transaction> transactions = Arrays.asList(
            new Transaction("ACC001", 500000L, "DEPOSIT", "SALARY"),        // 5000元
            new Transaction("ACC001", 150000L, "WITHDRAWAL", "SHOPPING"),   // 1500元
            new Transaction("ACC002", 1000000L, "DEPOSIT", "INVESTMENT"),   // 10000元
            new Transaction("ACC001", 250000L, "WITHDRAWAL", "BILLS"),      // 2500元
            new Transaction("ACC002", 300000L, "WITHDRAWAL", "SHOPPING"),   // 3000元
            new Transaction("ACC003", 800000L, "DEPOSIT", "SALARY"),        // 8000元
            new Transaction("ACC001", 200000L, "DEPOSIT", "BONUS"),         // 2000元
            new Transaction("ACC003", 100000L, "WITHDRAWAL", "ENTERTAINMENT") // 1000元
        );
        
        // 1. 按账户统计平均存款金额
        Map<String, Double> avgDepositByAccount = transactions.stream()
            .filter(t -> "DEPOSIT".equals(t.getType()))
            .collect(Collectors.groupingBy(
                Transaction::getAccountId,
                Collectors.averagingLong(Transaction::getAmount)
            ));
        
        System.out.println("Average deposit amount by account (分):");
        avgDepositByAccount.forEach((accountId, avgAmount) -> 
            System.out.printf("%s: %.2f 分 (%.2f 元)%n", 
                accountId, avgAmount, avgAmount / 100.0));
        // ACC001: 350000.00 分 (3500.00 元)
        // ACC002: 1000000.00 分 (10000.00 元)
        // ACC003: 800000.00 分 (8000.00 元)
        
        // 2. 按交易类型统计平均金额
        Map<String, Double> avgAmountByType = transactions.stream()
            .collect(Collectors.groupingBy(
                Transaction::getType,
                Collectors.averagingLong(Transaction::getAmount)
            ));
        
        System.out.println("\nAverage amount by transaction type:");
        avgAmountByType.forEach((type, avgAmount) -> 
            System.out.printf("%s: %.2f 分 (%.2f 元)%n", 
                type, avgAmount, avgAmount / 100.0));
        
        // 3. 按类别统计平均支出金额
        Map<String, Double> avgWithdrawalByCategory = transactions.stream()
            .filter(t -> "WITHDRAWAL".equals(t.getType()))
            .collect(Collectors.groupingBy(
                Transaction::getCategory,
                Collectors.averagingLong(Transaction::getAmount)
            ));
        
        System.out.println("\nAverage withdrawal amount by category:");
        avgWithdrawalByCategory.forEach((category, avgAmount) -> 
            System.out.printf("%s: %.2f 分 (%.2f 元)%n", 
                category, avgAmount, avgAmount / 100.0));
        
        // 4. 按月统计平均交易金额
        Map<YearMonth, Double> avgAmountByMonth = transactions.stream()
            .collect(Collectors.groupingBy(
                t -> YearMonth.from(t.getTimestamp()),
                Collectors.averagingLong(Transaction::getAmount)
            ));
        
        System.out.println("\nAverage transaction amount by month:");
        avgAmountByMonth.forEach((month, avgAmount) -> 
            System.out.printf("%s: %.2f 元%n", 
                month, avgAmount / 100.0));
    }
}

示例 3:文件系统分析

java
class FileInfo {
    private String name;
    private String extension;
    private long size;  // 字节
    private LocalDateTime lastModified;
    private String path;
    
    public FileInfo(String name, String extension, long size, String path) {
        this.name = name;
        this.extension = extension;
        this.size = size;
        this.path = path;
        this.lastModified = LocalDateTime.now();
    }
    
    // getters
    public String getName() { return name; }
    public String getExtension() { return extension; }
    public long getSize() { return size; }
    public LocalDateTime getLastModified() { return lastModified; }
    public String getPath() { return path; }
}

public class FileSystemAnalysis {
    public static void main(String[] args) {
        List<FileInfo> files = Arrays.asList(
            new FileInfo("document1", "pdf", 2_048_000L, "/docs"),
            new FileInfo("presentation", "pptx", 5_120_000L, "/presentations"),
            new FileInfo("spreadsheet", "xlsx", 3_072_000L, "/spreadsheets"),
            new FileInfo("image1", "jpg", 1_024_000L, "/images"),
            new FileInfo("document2", "pdf", 1_536_000L, "/docs"),
            new FileInfo("video1", "mp4", 50_000_000L, "/videos"),
            new FileInfo("image2", "png", 2_048_000L, "/images"),
            new FileInfo("code1", "java", 256_000L, "/code"),
            new FileInfo("document3", "docx", 4_096_000L, "/docs"),
            new FileInfo("archive1", "zip", 10_240_000L, "/archives")
        );
        
        // 1. 按文件类型统计平均文件大小
        Map<String, Double> avgSizeByExtension = files.stream()
            .collect(Collectors.groupingBy(
                FileInfo::getExtension,
                Collectors.averagingLong(FileInfo::getSize)
            ));
        
        System.out.println("Average file size by extension (bytes):");
        avgSizeByExtension.forEach((ext, avgSize) -> 
            System.out.printf("%s: %,.2f bytes (%.2f MB)%n", 
                ext, avgSize, avgSize / (1024.0 * 1024.0)));
        
        // 2. 按目录统计平均文件大小
        Map<String, Double> avgSizeByDirectory = files.stream()
            .collect(Collectors.groupingBy(
                file -> {
                    // 提取目录名
                    String path = file.getPath();
                    return path.startsWith("/") ? path : "/" + path;
                },
                Collectors.averagingLong(FileInfo::getSize)
            ));
        
        System.out.println("\nAverage file size by directory:");
        avgSizeByDirectory.forEach((dir, avgSize) -> 
            System.out.printf("%s: %,.2f bytes%n", dir, avgSize));
        
        // 3. 统计大文件(> 1MB)的平均大小
        Double avgLargeFileSize = files.stream()
            .filter(file -> file.getSize() > 1_048_576L) // 1 MB
            .collect(Collectors.averagingLong(FileInfo::getSize));
        
        System.out.printf("\nAverage size of large files (>1MB): %,.2f bytes%n", 
            avgLargeFileSize);
        
        // 4. 按文件大小范围分组统计
        Map<String, Double> avgSizeByRange = files.stream()
            .collect(Collectors.groupingBy(
                file -> {
                    long size = file.getSize();
                    if (size < 1024) return "小于1KB";
                    else if (size < 1_048_576) return "1KB-1MB";
                    else if (size < 10_485_760) return "1MB-10MB";
                    else if (size < 104_857_600) return "10MB-100MB";
                    else return "大于100MB";
                },
                Collectors.averagingLong(FileInfo::getSize)
            ));
        
        System.out.println("\nAverage size by size range:");
        avgSizeByRange.entrySet().stream()
            .sorted(Map.Entry.comparingByKey())
            .forEach(entry -> 
                System.out.printf("%s: %,.2f bytes%n", 
                    entry.getKey(), entry.getValue()));
    }
}