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

Java Stream API:如何用方法引用简化分组计算的重复代码?

解决分组统计逻辑重复:用方法引用替代重复Lambda

嘿,我来帮你搞定这个重复代码的问题!你现在在按不同维度(月份、年份、regionId、centerId)分组时,统计amount1总和和percent1平均值的逻辑完全重复,这时候把这段逻辑抽成独立方法,再用方法引用来替代Lambda就完美了。

先回顾下你的原始代码:

实体类与数据定义

class Person {
    private ZonedDateTime date ;
    private int regionId;
    private int centerId;
    private int amount1;
    private float percent1;
    
    // 别忘了添加getter方法哦,不然stream里的getDate()、getAmount1()这些调用会报错
    public ZonedDateTime getDate() { return date; }
    public int getRegionId() { return regionId; }
    public int getCenterId() { return centerId; }
    public int getAmount1() { return amount1; }
    public float getPercent1() { return percent1; }
}
List<Person> entityList = new ArrayList<>();

现有按月份分组实现

listPerson.stream()
    .collect(Collectors.groupingBy(i -> i.getDate().getMonth(),Collectors.collectingAndThen(Collectors.toList(), l -> {
        Integer sumAmount1 = l.stream().collect(Collectors.summingInt(i -> i.getAmount1()));
        Double avgPerc1 = l.stream().collect(Collectors.averagingDouble(i -> i.getPercent1()));
        List<String> data = new ArrayList<>();
        data.add(Integer.toString(sumAmount1));
        data.add(Double.toString(avgPerc1));
        return data;
    } ))).forEach((k,v) -> System.out.println(k.getValue() + "-" + v.toString()));

核心解决方案:提取公共统计方法

我们把重复的统计逻辑抽成一个静态方法,这样不管按什么维度分组,都可以直接引用这个方法,不用重复写Lambda。

1. 提取统计逻辑到静态方法

在你的项目里找个合适的类(比如和Person同包的工具类,或者直接在Person类里)添加这个静态方法:

public static List<String> computePersonStats(List<Person> personList) {
    // 用方法引用替代Lambda,让代码更简洁
    int totalAmount = personList.stream().collect(Collectors.summingInt(Person::getAmount1));
    double avgPercent = personList.stream().collect(Collectors.averagingDouble(Person::getPercent1));
    
    List<String> stats = new ArrayList<>();
    stats.add(String.valueOf(totalAmount));
    stats.add(String.valueOf(avgPercent));
    return stats;
}

2. 用方法引用替换重复Lambda

现在不管按哪个维度分组,都可以直接用YourClassName::computePersonStats来替代原来的Lambda,代码瞬间清爽很多:

按月份分组

listPerson.stream()
    .collect(Collectors.groupingBy(
        person -> person.getDate().getMonth(),
        Collectors.collectingAndThen(Collectors.toList(), YourClassName::computePersonStats)
    ))
    .forEach((month, stats) -> System.out.println(month.getValue() + "-" + stats));

注意:把YourClassName替换成你实际存放computePersonStats方法的类名

按年份分组

listPerson.stream()
    .collect(Collectors.groupingBy(
        person -> person.getDate().getYear(),
        Collectors.collectingAndThen(Collectors.toList(), YourClassName::computePersonStats)
    ))
    .forEach((year, stats) -> System.out.println(year + "-" + stats));

按regionId分组

listPerson.stream()
    .collect(Collectors.groupingBy(
        Person::getRegionId, // 这里也可以用方法引用简化
        Collectors.collectingAndThen(Collectors.toList(), YourClassName::computePersonStats)
    ))
    .forEach((regionId, stats) -> System.out.println(regionId + "-" + stats));

按centerId分组

listPerson.stream()
    .collect(Collectors.groupingBy(
        Person::getCenterId, // 同样用方法引用简化
        Collectors.collectingAndThen(Collectors.toList(), YourClassName::computePersonStats)
    ))
    .forEach((centerId, stats) -> System.out.println(centerId + "-" + stats));

额外优化:用自定义对象替代List

其实用List<String>来存统计结果不够直观,建议你创建一个专门的统计结果类,比如PersonStats,这样代码可读性和可维护性都会更好:

class PersonStats {
    private int totalAmount1;
    private double averagePercent1;

    public PersonStats(int totalAmount1, double averagePercent1) {
        this.totalAmount1 = totalAmount1;
        this.averagePercent1 = averagePercent1;
    }

    // 重写toString方法,方便打印输出
    @Override
    public String toString() {
        return String.format("总金额: %d, 平均百分比: %.2f", totalAmount1, averagePercent1);
    }

    // 可以按需添加getter方法
}

然后修改静态方法:

public static PersonStats computePersonStats(List<Person> personList) {
    int totalAmount = personList.stream().mapToInt(Person::getAmount1).sum();
    // 用orElse处理空列表的情况,避免NoSuchElementException
    double avgPercent = personList.stream()
                                 .mapToDouble(Person::getPercent1)
                                 .average()
                                 .orElse(0.0);
    return new PersonStats(totalAmount, avgPercent);
}

这时候打印的结果会更友好:

.forEach((groupKey, stats) -> System.out.println(groupKey + "-" + stats));

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 07:23:51