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

如何使用Java Streams对Map值按指定区间分组并统计元素数量?

嘿,这个需求用Java Streams完全可以优雅实现,我给你拆解一下具体步骤,附上完整代码和解释:

使用Java Streams实现按区间分组统计

我们要解决两个核心问题:一是把每个数值映射到对应的区间,二是确保所有要求的区间都出现在结果中(哪怕该区间没有元素,也要显示0)。

步骤1:准备原始数据

先初始化题目给出的Map:

Map<String, BigDecimal> data = new HashMap<>();
data.put("A", new BigDecimal(12));
data.put("B", new BigDecimal(23));
data.put("C", new BigDecimal(67));
data.put("D", new BigDecimal(99));

步骤2:定义区间规则

我们可以先明确所有需要的区间,以及每个数值归属区间的判断逻辑。这里把区间和判断条件绑定,方便后续统一处理:

// 定义所有目标区间,同时指定每个区间的判断规则(保持顺序)
List<Map.Entry<String, Predicate<BigDecimal>>> intervals = Arrays.asList(
    new AbstractMap.SimpleEntry<>("0-25", num -> num.compareTo(BigDecimal.ZERO) >= 0 && num.compareTo(new BigDecimal(25)) <= 0),
    new AbstractMap.SimpleEntry<>("26-50", num -> num.compareTo(new BigDecimal(26)) >= 0 && num.compareTo(new BigDecimal(50)) <= 0),
    new AbstractMap.SimpleEntry<>("51-75", num -> num.compareTo(new BigDecimal(51)) >= 0 && num.compareTo(new BigDecimal(75)) <= 0),
    new AbstractMap.SimpleEntry<>("76-100", num -> num.compareTo(new BigDecimal(76)) >= 0 && num.compareTo(new BigDecimal(100)) <= 0)
);

注意:BigDecimal的比较必须用compareTo方法,不能直接用>/<,因为它是对象类型,直接比较会出错。

步骤3:统计各区间元素数量

用Collectors.groupingBy把数值按区间分组,同时统计每组的元素个数:

// 先统计有数据的区间的元素数量
Map<String, Long> counted = data.values().stream()
    .collect(Collectors.groupingBy(
        num -> intervals.stream()
            .filter(entry -> entry.getValue().test(num))
            .map(Map.Entry::getKey)
            .findFirst()
            .orElse(null), // 处理不在任何区间的数值(这里题目数据都在区间内,可忽略)
        Collectors.counting()
    ));

步骤4:补全空区间的0值

默认的groupingBy只会生成有元素的区间键,所以我们需要把所有目标区间都加入结果,没有元素的填0:

// 构建最终结果,确保所有区间都存在,空区间填充0
Map<String, Long> result = intervals.stream()
    .map(Map.Entry::getKey)
    .collect(Collectors.toMap(
        key -> key,
        key -> counted.getOrDefault(key, 0L),
        (oldVal, newVal) -> oldVal, // 合并逻辑,这里不会触发
        LinkedHashMap::new // 可选:保持区间的定义顺序
    ));

验证结果

运行后输出结果:

0-25: 2
26-50: 0
51-75: 1
76-100: 1

优化写法(可选)

如果觉得区间判断逻辑写在流里太繁琐,可以抽成一个单独的方法,让代码更清晰:

private static String getInterval(BigDecimal num) {
    if (num.compareTo(new BigDecimal(25)) <= 0) return "0-25";
    else if (num.compareTo(new BigDecimal(50)) <= 0) return "26-50";
    else if (num.compareTo(new BigDecimal(75)) <= 0) return "51-75";
    else if (num.compareTo(new BigDecimal(100)) <= 0) return "76-100";
    else return null; // 处理超出范围的数值
}

然后分组时直接调用这个方法:

Map<String, Long> counted = data.values().stream()
    .collect(Collectors.groupingBy(
        YourClassName::getInterval,
        Collectors.counting()
    ));

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 10:23:04