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
相关产品推荐
相关产品推荐

