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

