如何用Java 8 Lambda Stream按指定时间段分组计算平均值?
解决方案:Java 8 Lambda按时间区间计算平均值
没问题,我来帮你搞定这个需求!首先得明确几个关键点:咱们需要忽略日期部分,只提取时间的时分,然后按照指定的两个区间分组,最后计算每组的value平均值。
第一步:完善Obj类(添加必要的Getter)
你的Obj类里属性是private的,Lambda需要访问这些属性,所以得加上Getter方法:
import java.util.Date; public class Obj { private Date date; private int value; // 构造方法(方便测试生成实例) public Obj(Date date, int value) { this.date = date; this.value = value; } // Getter方法,供Lambda访问属性 public Date getDate() { return date; } public int getValue() { return value; } }
第二步:核心实现代码
下面是完整的逻辑实现,我会逐段给你解释:
import java.time.LocalTime; import java.time.ZoneId; import java.util.*; import java.util.stream.Collectors; public class TimeIntervalAverage { public static void main(String[] args) { // 模拟示例数据:先把字符串转成Date,实际项目如果用Java8+建议直接用新日期API SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH.mm"); List<Obj> objList = new ArrayList<>(); try { objList.add(new Obj(sdf.parse("2010-02-01 2.00"), 20)); objList.add(new Obj(sdf.parse("2010-02-01 4.00"), 5)); objList.add(new Obj(sdf.parse("2010-02-02 3.00"), 55)); objList.add(new Obj(sdf.parse("2010-02-02 3.30"), 7)); objList.add(new Obj(sdf.parse("2010-02-03 5.00"), 88)); objList.add(new Obj(sdf.parse("2010-02-03 5.20"), 1)); } catch (Exception e) { e.printStackTrace(); } // 定义两个时间区间的边界值 LocalTime interval1Start = LocalTime.of(2, 0); LocalTime interval1End = LocalTime.of(4, 0); LocalTime interval2Start = LocalTime.of(4, 1); LocalTime interval2End = LocalTime.of(6, 0); // 核心逻辑:分组+计算平均值 Map<String, Double> intervalAverageMap = objList.stream() .collect(Collectors.groupingBy( // 分组规则:判断当前对象的时间属于哪个区间 obj -> { // 把Date转成LocalTime,只保留时分部分,忽略日期 LocalTime currentTime = obj.getDate().toInstant() .atZone(ZoneId.systemDefault()) .toLocalTime(); // 按需求判断区间归属:4:00属于第一个区间,4:01属于第二个 if (!currentTime.isBefore(interval1Start) && !currentTime.isAfter(interval1End)) { return "2:00-4:00"; } else if (!currentTime.isBefore(interval2Start) && !currentTime.isAfter(interval2End)) { return "4:01-6:00"; } else { // 不属于目标区间的可以标记为"其他",或者根据业务需求处理 return "其他"; } }, // 对每组的value计算平均值 Collectors.averagingInt(Obj::getValue) )); // 输出最终结果 intervalAverageMap.forEach((interval, average) -> System.out.printf("区间%s的平均值:%.2f%n", interval, average)); } }
代码细节解释
- 日期转换:把旧的
Date转成LocalTime是为了方便只处理时分部分,这里用了系统默认时区,如果你的业务有指定时区,可以替换成ZoneId.of("Asia/Shanghai")这类具体时区。 - 分组逻辑:通过Lambda表达式精准判断时间归属,确保边界值(比如4:00、4:01)符合你的需求。
- 平均值计算:用
Collectors.averagingInt直接对每组的value求平均,返回的是Double类型,方便保留小数。
运行结果
执行这段代码后,会输出:
区间2:00-4:00的平均值:21.75 区间4:01-6:00的平均值:44.50
完全匹配你给出的示例数据计算结果!
额外优化建议
如果你的项目已经在使用Java 8+的日期API,建议把Obj类里的Date改成LocalDateTime,这样处理时间会更简洁,避免时区问题。比如:
import java.time.LocalDateTime; public class Obj { private LocalDateTime dateTime; private int value; public Obj(LocalDateTime dateTime, int value) { this.dateTime = dateTime; this.value = value; } public LocalDateTime getDateTime() { return dateTime; } public int getValue() { return value; } }
此时提取时间部分直接用obj.getDateTime().toLocalTime()即可,不需要再处理Date转Instant的步骤。
内容的提问来源于stack exchange,提问作者Parry Markus
相关产品推荐
相关产品推荐

