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

Java 8使用Lambda与Stream实现自定义规则元素频率计数

问题描述

现有元素为"na","na","na","uk","uk"的字符串列表,需按照如下自定义规则统计每个元素的出现频率:

  • 元素首次出现时,对应键的初始计数值为1
  • 后续重复遇到相同元素时,若该键当前已存计数值为偶数,则累加1
  • 若当前已存计数值为奇数,则累加2

传统for循环的参考实现如下:

List<String> streamer = Arrays.asList("na", "na", "na", "uk", "uk");
Map<String, Integer> m = new HashMap<>();

for(String s:streamer) {
    if (m.containsKey(s)) {
        if(m.get(s) % 2 == 0)
            m.put(s, m.get(s) + 1);
        else
            m.put(s,m.get(s)+2);
    }
    else
        m.put(s,1);
}
System.out.println("CUSTOM Frequency::::" + m); 

现在需要用Java 8的Stream流与Lambda表达式实现完全一致的逻辑,已写出基础的分组计数框架,但不知道如何替换Collectors.counting()实现自定义计数效果,现有基础代码如下:

Map<String, Long>map4 = streamer.stream()
    .collect(Collectors.groupingBy(
        Function.identity(),
        Collectors.counting())); // 如何替换此处的counting实现自定义计数?
实现方案

直接使用Collector.of自定义下游收集器,1:1复刻原循环的计数逻辑即可,完整可运行代码如下:

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collector;
import java.util.stream.Collectors;

public class CustomFrequencyCount {
    public static void main(String[] args) {
        List<String> streamer = Arrays.asList("na", "na", "na", "uk", "uk");
        
        Map<String, Integer> customCountMap = streamer.stream()
                .collect(Collectors.groupingBy(
                        Function.identity(),
                        // 自定义收集器替换原有Collectors.counting()
                        Collector.of(
                                // 初始化可变计数容器:用长度为1的int数组规避Integer不可变问题,初始值为0
                                () -> new int[1],
                                // 累加逻辑:完全对齐原for循环的判断规则
                                (countContainer, currentItem) -> {
                                    int currentVal = countContainer[0];
                                    if (currentVal == 0) {
                                        // 首次遇到该元素,设置初始值1
                                        countContainer[0] = 1;
                                    } else if (currentVal % 2 == 0) {
                                        // 当前值为偶数,累加1
                                        countContainer[0] = currentVal + 1;
                                    } else {
                                        // 当前值为奇数,累加2
                                        countContainer[0] = currentVal + 2;
                                    }
                                },
                                // 并行流场景下的分区合并逻辑,逐次累加保证计数规则一致
                                (container1, container2) -> {
                                    int mergeTemp = container1[0];
                                    int addTimes = container2[0];
                                    for (int i = 0; i < addTimes; i++) {
                                        mergeTemp = mergeTemp % 2 == 0 ? mergeTemp + 1 : mergeTemp + 2;
                                    }
                                    container1[0] = mergeTemp;
                                    return container1;
                                },
                                // 收尾操作:将int数组中的计数值转为Integer返回
                                countContainer -> countContainer[0]
                        )
                ));
        
        System.out.println("CUSTOM Frequency::::" + customCountMap);
        // 输出结果与原for循环完全一致:CUSTOM Frequency::::{na=5, uk=3}
    }
}

逻辑说明

  • 该实现没有简化原规则的判断分支,哪怕当前样例中计数永远为奇数、偶数累加分支不会触发,也完全对齐了原有代码的执行逻辑
  • 自定义收集器同时支持顺序流和并行流场景,合并逻辑做了适配,不会出现并行计算结果不一致的问题
  • 最终返回的Map value类型为Integer,和原for循环实现的Map类型一致,不需要额外做类型转换

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 00:31:16