EnumSet 是 Java 中专为枚举设计的高性能位运算集合,操作均为 O(1) 单指令位运算,比 HashSet、TreeSet 更快更省内存;需用静态工厂方法创建,遍历按声明顺序,非线程安全。

EnumSet 是 Java 中专为枚举类型设计的高性能集合,所有操作本质都是位运算,不涉及哈希计算、对象创建或扩容,因此比 HashSet、TreeSet 更快更省内存。它不是“更快一点”,而是从底层机制上就规避了通用集合的开销。
创建要选对工厂方法
EnumSet 没有 public 构造器,必须用静态工厂方法。不同场景对应不同方法,选错会影响可读性和潜在性能:
- EnumSet.noneOf(Type.class):初始化空集合,开销最小,适合后续按条件动态添加
-
EnumSet.of(e1, e2, ...):适用于固定少量值(最多 5 个参数重载),语义清晰;超过时可用
of(e1,e2).addAll(EnumSet.of(e3,e4)) - EnumSet.allOf(Type.class):一次性包含全部枚举值,底层直接置高位,比循环 add 快一个数量级
-
EnumSet.range(from, to):仅当枚举声明顺序连续时安全(如
MONDAY到FRIDAY),内部按ordinal()线性截取;若中间有跳变,结果不可靠
核心操作全是单指令位运算
只要枚举常量 ≤64 个,EnumSet 底层只用一个 long 存储,所有基础操作都映射为 CPU 级位指令:
- contains(e) → 检查对应 bit 是否为 1(一次位与 + 移位)
- add(e) / remove(e) → 对应位置执行 or 或 xor
-
retainAll(s) → 两个 long 值按位与(
a & b) -
removeAll(s) → 按位与非(
a & ~b) -
clear() → 直接清空 long 字段,比新建
noneOf更轻量
这些操作时间复杂度恒为 O(1),且常数极小,不受集合当前大小影响。
立即学习“Java免费学习笔记(深入)”;
集合运算要善用语义化方法
避免手动遍历或多次调用 contains(),优先使用内置集合运算:
- 判断是否同时拥有多个权限:
perms.containsAll(required),内部做了位与优化,比循环contains()高效得多 - 获取用户不具备的权限:
EnumSet.complementOf(perms),但注意补集范围是整个枚举类(含未来新增项) - 筛选共有的状态:
currentStates.retainAll(validTransitions),一行完成交集过滤 - 权限继承或降级:
userPerms.removeAll(restricted),等价于bits & ~restrictedBits,无循环开销
使用中要注意几个关键边界
高效的前提是守规矩:
- 只能存同一枚举类型的实例,混入其他类型编译报错;不能存
null,否则运行时报NullPointerException - 遍历顺序永远是枚举声明顺序(
ordinal()升序),不是插入顺序,也不支持自定义排序 - 非线程安全,多线程写入需外层同步;如需只读视图,用
Collections.unmodifiableSet()包装 - 序列化后反序列化要求目标环境枚举类存在且常量顺序未变,增删中间值会导致数据错位
- 与 Stream 配合时,建议先转数组再处理(
set.toArray()),避免反复调用 iterator


















