
使用treemap配合string.case_insensitive_order比较器,可在保持键值唯一性(忽略大小写)的同时,以单词首次出现的原始大小写形式作为最终键,精准统计词频。
在处理字符串词频统计时,若需“不区分大小写匹配,但保留首次出现的原始大小写作为键”,直接使用HashMap或ConcurrentHashMap并手动遍历判断(如原代码所示)不仅逻辑复杂、易出错,且存在并发安全与性能隐患(例如重复put、竞态条件、O(n²)时间复杂度)。更优雅、高效且线程安全(如需)的方案是借助TreeMap的定制化排序能力。
TreeMap支持传入Comparator super K>构造,而String.CASE_INSENSITIVE_ORDER正是一个预定义的、忽略大小写的Comparator
推荐写法(简洁、安全、符合语义):
import java.util.TreeMap; final TreeMapwordCount = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); final String[] words = {"AA", "Bb", "Aa", "aa", "BB"}; for (String word : words) { wordCount.merge(word, 1, Integer::sum); } System.out.println(wordCount); // 输出: {AA=3, Bb=2}
对于更复杂的示例:
{"AAa", "aaa", "BBB", "bbb", "BbB", "AaA", "AAc"}
执行后输出:{AAa=3, BBB=3, AAc=1}
✅ "AAa"首次出现 → 成为键;"AaA"和"aaa"与其忽略大小写相等 → 累加至AAa;
✅ "BBB"首次出现 → 成为键;"bbb"和"BbB"匹配 → 累加至BBB;
✅ "AAc"无其他变体 → 单独计为1。
⚠️ 注意事项:
立即学习“Java免费学习笔记(深入)”;
- TreeMap非线程安全;若需并发环境使用,请搭配Collections.synchronizedSortedMap()包装,或改用ConcurrentSkipListMap(它也接受Comparator,且线程安全):
final ConcurrentSkipListMap
safeMap = new ConcurrentSkipListMap<>(String.CASE_INSENSITIVE_ORDER); - 不要误用HashMap+toLowerCase()预处理:这会丢失原始大小写形式,无法满足“以首次出现为准”的需求;
- merge()方法是Java 8引入的原子操作,比手动get/put更简洁可靠,避免空指针与竞态。
总结:以TreeMap(或ConcurrentSkipListMap)配合String.CASE_INSENSITIVE_ORDER为核心,辅以merge()语义化更新,即可一行逻辑解决“大小写不敏感分组 + 原始形式定键”的经典词频统计问题。










