本文详解如何使用 HashMap 统计字符串中各单词出现频次,涵盖基础循环遍历、merge() 方法优化及 Stream API 函数式实现三种专业方案,并附完整可运行示例与关键注意事项。
本文详解如何使用 hashmap 统计字符串中各单词出现频次,涵盖基础循环遍历、`merge()` 方法优化及 stream api 函数式实现三种专业方案,并附完整可运行示例与关键注意事项。
在 Java 中构建一个高效的单词计数器(Word Map Counter),核心目标是:将输入字符串按空格切分为单词数组,然后统计每个单词的出现次数,并以 Map<String, Integer> 形式返回结果。下面分三种递进方式展开说明,兼顾可读性、健壮性与现代 Java 实践。
✅ 方式一:基础显式逻辑(适合初学者理解)
使用 split(" ") 切分字符串后,通过 containsKey() 显式判断单词是否已存在,再分别执行初始化或累加:
private static Map<String, Integer> countWords(String text) {
if (text == null || text.trim().isEmpty()) {
return new HashMap<>();
}
Map<String, Integer> wordMap = new HashMap<>();
String[] words = text.trim().split("\s+"); // 使用 \s+ 更鲁棒:支持多空格、制表符等
for (String word : words) {
if (word.isEmpty()) continue; // 过滤空字符串(如连续空格导致)
wordMap.put(word, wordMap.getOrDefault(word, 0) + 1);
}
return wordMap;
}? 提示:此处用 getOrDefault(word, 0) 替代 containsKey() + get() 的两步操作,代码更简洁且线程安全(无竞态风险)。
✅ 方式二:merge() 方法(推荐日常使用)
Java 8 引入的 Map.merge() 可一行完成“存在则合并,不存在则插入”逻辑,语义清晰、性能优良:
使用tbot机器ID身份文件配合tsh CLI,通过Teleport访问控制SSH登录托管主机或执行远程命令。
立即学习“Java免费学习笔记(深入)”;
private static Map<String, Integer> countWords(String text) {
if (text == null || text.trim().isEmpty()) return Map.of(); // 返回不可变空Map(Java 9+)
Map<String, Integer> wordMap = new HashMap<>();
for (String word : text.trim().split("\s+")) {
if (!word.isEmpty()) {
wordMap.merge(word, 1, Integer::sum); // key, defaultValue, remappingFunction
}
}
return wordMap;
}✅ 方式三:Stream API 函数式风格(适合简洁表达)
结合 Arrays.stream()、Collectors.groupingBy() 与 Collectors.summingInt(),实现声明式统计:
import java.util.*;
import java.util.stream.Collectors;
import static java.util.stream.Collectors.*;
private static Map<String, Integer> countWords(String text) {
if (text == null || text.trim().isEmpty()) return Collections.emptyMap();
return Arrays.stream(text.trim().split("\s+"))
.filter(word -> !word.isEmpty())
.collect(groupingBy(Function.identity(), summingInt(w -> 1)));
}⚠️ 关键注意事项
- 空值与空白处理:务必校验 null 和全空白字符串,避免 NullPointerException 或误统计空项;
- 分隔符健壮性:优先使用 split("\s+") 而非 split(" "),以兼容制表符、换行符及多个连续空格;
- 大小写敏感性:如需忽略大小写,可在分割前统一转为小写:text.toLowerCase().split("\s+");
- 并发场景:若需多线程安全,可选用 ConcurrentHashMap 并配合 compute() 方法;
- 性能考量:对超长文本,Stream 方案虽优雅但有轻微开销;高频调用场景建议使用 merge() 或 getOrDefault()。
以上三种实现均通过相同测试用例验证:
String input = "Hello world Hello all";
System.out.println(countWords(input)); // 输出:{Hello=2, world=1, all=1}选择哪一种取决于项目规范、JDK 版本及团队偏好——但无论哪种,都应以健壮性为前提,可读性为基石,性能为保障。

















