EnumSet & EnumMap
When your keys or elements are enum constants, EnumSet and EnumMap are the fastest collections in Java’s toolbox. Both live in java.util, work exclusively with enums, and are backed by extremely compact internal structures — making them quicker and more memory-efficient than their general-purpose siblings like HashSet or HashMap.
Why EnumSet and EnumMap Exist
General-purpose collections (HashSet, HashMap) use hashing and object references — flexible, but heavyweight for enums. Because enum constants have a known count and a fixed ordinal (0, 1, 2, …), Java can replace hash buckets with a plain bit vector or a tightly-packed array, giving you O(1) everything with almost zero overhead.
EnumSet
EnumSet<E extends Enum<E>> is a Set implementation designed exclusively for enum values. Every operation — add, remove, contains, iteration — runs in constant time and uses a single long (or an array of longs for large enums) as its backing store.
Creating an EnumSet
import java.util.EnumSet;
enum Day { MON, TUE, WED, THU, FRI, SAT, SUN }
public class EnumSetDemo {
public static void main(String[] args) {
// All constants
EnumSet<Day> week = EnumSet.allOf(Day.class);
System.out.println("Full week: " + week);
// A hand-picked subset
EnumSet<Day> workdays = EnumSet.of(Day.MON, Day.TUE, Day.WED, Day.THU, Day.FRI);
System.out.println("Workdays: " + workdays);
// A contiguous range (ordinal order)
EnumSet<Day> weekend = EnumSet.range(Day.SAT, Day.SUN);
System.out.println("Weekend: " + weekend);
// Complement — everything NOT in workdays
EnumSet<Day> offDays = EnumSet.complementOf(workdays);
System.out.println("Off days: " + offDays);
// Start empty, then add
EnumSet<Day> empty = EnumSet.noneOf(Day.class);
empty.add(Day.FRI);
System.out.println("TGIF set: " + empty);
}
}
Output:
Full week: [MON, TUE, WED, THU, FRI, SAT, SUN]
Workdays: [MON, TUE, WED, THU, FRI]
Weekend: [SAT, SUN]
Off days: [SAT, SUN]
TGIF set: [FRI]
Factory Methods at a Glance
| Method | What it creates |
|---|---|
EnumSet.allOf(E.class) | All constants of the enum |
EnumSet.noneOf(E.class) | An empty set (same element type) |
EnumSet.of(E e, E... rest) | A set with the listed constants |
EnumSet.range(E from, E to) | Constants from from to to (inclusive, ordinal order) |
EnumSet.complementOf(EnumSet<E>) | All constants not in the given set |
EnumSet.copyOf(Collection<E>) | A set initialized from any collection of enums |
Note:
EnumSetis not thread-safe. Wrap it withCollections.synchronizedSet()if multiple threads share it.
EnumSet as a Set
EnumSet fully implements java.util.Set, so all the familiar operations work:
import java.util.EnumSet;
enum Permission { READ, WRITE, EXECUTE, DELETE }
public class PermissionCheck {
public static void main(String[] args) {
EnumSet<Permission> userPerms = EnumSet.of(Permission.READ, Permission.WRITE);
System.out.println("Can read? " + userPerms.contains(Permission.READ));
System.out.println("Can delete? " + userPerms.contains(Permission.DELETE));
userPerms.add(Permission.EXECUTE);
userPerms.remove(Permission.WRITE);
System.out.println("Updated: " + userPerms);
}
}
Output:
Can read? true
Can delete? false
Updated: [READ, EXECUTE]
Iterating an EnumSet
Iteration follows the natural ordinal order of the enum — always predictable, never random:
for (Day d : EnumSet.range(Day.MON, Day.FRI)) {
System.out.println("Workday: " + d);
}
Tip: Because the iteration order matches your enum declaration order, EnumSet is a cleaner alternative to a sorted
HashSetwhenever your elements are enums.
EnumMap
EnumMap<K extends Enum<K>, V> is a Map implementation where the keys must be enum constants. Internally it uses a plain Object[] array indexed by each constant’s ordinal, making every get and put a single array lookup — as fast as it gets.
Creating and Using an EnumMap
import java.util.EnumMap;
import java.util.Map;
enum Planet { MERCURY, VENUS, EARTH, MARS }
public class EnumMapDemo {
public static void main(String[] args) {
EnumMap<Planet, Double> gravity = new EnumMap<>(Planet.class);
gravity.put(Planet.MERCURY, 3.7);
gravity.put(Planet.VENUS, 8.87);
gravity.put(Planet.EARTH, 9.81);
gravity.put(Planet.MARS, 3.72);
for (Map.Entry<Planet, Double> entry : gravity.entrySet()) {
System.out.printf("%-10s → %.2f m/s²%n",
entry.getKey(), entry.getValue());
}
}
}
Output:
MERCURY → 3.70 m/s²
VENUS → 8.87 m/s²
EARTH → 9.81 m/s²
MARS → 3.72 m/s²
Like EnumSet, iteration order matches the enum’s declaration order — no sorting needed.
Practical Pattern: Counting with EnumMap
A common real-world use case is grouping or counting things by category:
import java.util.EnumMap;
enum Priority { LOW, MEDIUM, HIGH, CRITICAL }
public class TaskCounter {
public static void main(String[] args) {
EnumMap<Priority, Integer> counts = new EnumMap<>(Priority.class);
// Initialize all buckets to zero
for (Priority p : Priority.values()) {
counts.put(p, 0);
}
// Simulate incoming tasks
Priority[] incoming = {Priority.HIGH, Priority.LOW, Priority.HIGH,
Priority.CRITICAL, Priority.MEDIUM, Priority.HIGH};
for (Priority p : incoming) {
counts.merge(p, 1, Integer::sum);
}
counts.forEach((p, n) -> System.out.println(p + ": " + n + " task(s)"));
}
}
Output:
LOW: 1 task(s)
MEDIUM: 1 task(s)
HIGH: 3 task(s)
CRITICAL: 1 task(s)
Note:
EnumMapallowsnullvalues but notnullkeys. Attempting to use anullkey throws aNullPointerException.
Under the Hood
EnumSet — bit manipulation
EnumSet is abstract. The JDK provides two concrete subclasses you never reference directly:
RegularEnumSet— used when the enum has 64 or fewer constants. The entire set fits in a singlelongfield. Adding constantXsets bitX.ordinal()in thatlong;containsis a single bitwise AND; iteration scans set bits withLong.numberOfTrailingZeros. This is about as fast as a CPU can go.JumboEnumSet— used for enums with more than 64 constants. The bits are spread across along[]array.
The factory method EnumSet.of(...) automatically picks the right subclass, so you never need to think about it.
EnumMap — array lookup
EnumMap stores values in an Object[] vals array. Each put(key, value) call does vals[key.ordinal()] = value. Each get(key) call returns vals[key.ordinal()]. No hashing, no probing, no linked-list traversal — just a direct array index. This is why EnumMap benchmarks show it to be roughly 2–4× faster than a comparable HashMap for enum keys.
Memory footprint comparison
| Collection | Overhead for N=8 enum keys |
|---|---|
HashSet / HashMap | Node objects + hash table array |
EnumSet | 1 long (8 bytes) |
EnumMap | 1 Object[] of length 8 |
For small, fixed-domain key sets this difference is dramatic.
EnumSet vs HashSet — Quick Comparison
| Feature | EnumSet | HashSet |
|---|---|---|
| Key type | Enum only | Any object |
| Backing store | Bit vector (long) | Hash table |
| Performance | O(1), near zero overhead | O(1) average, higher constant |
| Null elements | Not allowed | One null allowed |
| Iteration order | Enum declaration order | Unspecified |
| Thread safety | Not thread-safe | Not thread-safe |
EnumMap vs HashMap — Quick Comparison
| Feature | EnumMap | HashMap |
|---|---|---|
| Key type | Enum only | Any object |
| Backing store | Object[] array | Hash table |
| Performance | O(1) array index | O(1) average |
| Null keys | Not allowed | One null allowed |
| Iteration order | Enum declaration order | Unspecified |
| Memory | Compact fixed array | Node objects |
When to Use Them
Use EnumSet when you need a set whose elements come from a fixed enum — permission flags, days of the week, feature toggles, state machines. It replaces the old int-bitmask pattern with something readable and type-safe.
Use EnumMap whenever your map keys are enum constants — routing tables, config-per-state, counting/grouping by category. Any time you would write Map<MyEnum, V>, prefer EnumMap<MyEnum, V>.
Tip: Prefer
EnumMapandEnumSetoverHashMap/HashSetany time your keys/elements are enums. The compiler enforces the correct types, your IDE autocompletes the constants, and the JVM runs the operations faster.
Related Topics
- Enums — understand enum constants, ordinals, and methods before using these collections
- Set Interface — the contract that
EnumSetimplements - Map Interface — the contract that
EnumMapimplements - HashSet — general-purpose set for non-enum elements
- HashMap — general-purpose map; compare internals with
EnumMap - Collections Utility Class — helper methods like
Collections.synchronizedSet()that apply toEnumSet