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

如何用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));
    }
}

代码细节解释

  1. 日期转换:把旧的Date转成LocalTime是为了方便只处理时分部分,这里用了系统默认时区,如果你的业务有指定时区,可以替换成ZoneId.of("Asia/Shanghai")这类具体时区。
  2. 分组逻辑:通过Lambda表达式精准判断时间归属,确保边界值(比如4:00、4:01)符合你的需求。
  3. 平均值计算:用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 06:30:45