enummap 比 hashmap 更快是因为其内部用数组存储,索引由枚举 ordinal() 直接决定,避免哈希计算、扩容和碰撞处理,get/put 稳定 o(1) 且内存更小,但要求键必须是枚举且预分配全部常量空间。

EnumMap 为什么比 HashMap 更快
因为 EnumMap 内部用数组而非哈希表存储,索引直接由枚举的 ordinal() 值决定,完全避免哈希计算、扩容、碰撞处理。只要枚举类不变,EnumMap 的 get/put 时间复杂度稳定是 O(1),且内存占用更小。
但代价是:键类型必须是枚举,且整个枚举类的所有常量都会预留空间(哪怕没存值)。比如有 100 个枚举常量,只 put 3 个,底层数组长度仍是 100。
- 适用场景:
State、EventType、HttpStatusCode这类常量数量可控、极少变更的枚举 - 不适用:
LogLevel若未来可能动态扩展(如插件新增级别),或枚举常量超千个且稀疏使用 - 注意:
EnumMap不是线程安全的,多线程写入需手动同步
正确初始化 EnumMap 的两种方式
必须在构造时指定枚举类,否则编译失败。不能像 HashMap 那样靠泛型推断:
// ✅ 正确:显式传入枚举类 EnumMap<dayofweek string> map = new EnumMap(DayOfWeek.class); // ❌ 编译错误:类型擦除后无法获取枚举类信息 // EnumMap<dayofweek string> map = new EnumMap();</dayofweek></dayofweek>
推荐用静态工厂方法 EnumMap.of()(Java 9+)快速构建小规模映射:
EnumMap<dayofweek boolean> workdays = EnumMap.of(
DayOfWeek.MONDAY, true,
DayOfWeek.TUESDAY, true,
DayOfWeek.WEDNESDAY, true,
DayOfWeek.THURSDAY, true,
DayOfWeek.FRIDAY, true
);</dayofweek>
put 和 get 的行为与 null 处理
EnumMap 允许 value 为 null,但 key 绝对不能为 null(否则抛 NullPointerException)。这和 HashMap 一致,但要注意:调用 get(key) 返回 null 时,无法区分“key 不存在”还是“value 显式设为 null”。
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
- 用
containsKey(key)明确判断 key 是否存在 - 用
computeIfAbsent(key, mappingFunction)安全地惰性初始化值 - 避免直接比较
map.get(k) == null来做业务分支
示例:
EnumMap<status string> statusMsg = new EnumMap(Status.class);
statusMsg.put(Status.PENDING, "等待处理");
statusMsg.put(Status.DONE, null); // 合法
if (statusMsg.containsKey(Status.DONE)) {
System.out.println("DONE 存在,值为:" + statusMsg.get(Status.DONE));
}</status>
遍历顺序和 keySet() 的特殊性
EnumMap 的迭代顺序永远是枚举常量声明顺序(即 ordinal() 升序),不是插入顺序,也不是哈希顺序。这是它可预测、适合状态机等场景的关键特性。
keySet()、values()、entrySet() 返回的集合都继承该顺序,且所有集合都是 EnumMap 的“活视图”——修改 map 会实时反映在集合中,反之亦然。
- 不要对
keySet()调用toArray()后再排序,它本来就是有序的 - 避免用
new ArrayList(map.keySet())多余拷贝,除非需要独立快照 -
entrySet().iterator()是最高效的遍历方式,避免反复调用get()
容易被忽略的一点:如果枚举类通过反射动态修改了常量顺序(极罕见),EnumMap 的行为将不可预期——所以别这么干。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










