All topics
library
intermediate

EnumSet & EnumMap

Use specialized, high-performance collections for enum keys/elements instead of HashSet/HashMap.

These two exploit one fact: enum constants have consecutive ordinals, so no hashing is needed.

EnumMap = a fixed-size mailbox row (one slot per apartment/enum). You go directly to slot 3 for enum ordinal 3. HashMap = a post office with hash lookups — much more overhead for a small, fixed set of keys.

Key Concepts

1
    EnumSet<Day> weekend = EnumSet.of(Day.SAT, Day.SUN);
    EnumMap<Day, String> hours = new EnumMap<>(Day.class);
    hours.put(Day.MON, "9-5");
2
EnumSet is a bit vector. One long, one bit per constant, so membership is a bitwise AND:
EnumSetlong
3
    contains   O(1), a single bit test
    add        O(1)
    union, intersection   O(1) for the whole set
4
That makes it both faster and far smaller than a HashSet — no node objects, no hash computation, no collision handling.
HashSet
5
EnumMap is a plain array indexed by ordinal(). get is one array access, with no hashing and no collisions.
EnumMapordinal()get
6
The factory methods are the nice part of EnumSet.
    EnumSet.of(READ, WRITE)
    EnumSet.allOf(Day.class)            every constant
    EnumSet.noneOf(Day.class)           empty, correctly typed
    EnumSet.range(MON, FRI)             a declaration-order range
    EnumSet.complementOf(weekend)       everything else
EnumSet
7
complementOf and range have no equivalent in the general collections, and both read far better than the loop you would write.
complementOfrange
8
Use it instead of a bitmask.
    int perms = READ | WRITE;                  // what type is this? any int
    EnumSet<Perm> perms = EnumSet.of(READ, WRITE);   // type-safe, printable
9
The bitmask is the traditional trick for a compact flag set. EnumSet is just as compact and cannot be passed a meaningless value.
EnumSet
10
Iteration follows declaration order, not insertion, for both classes. So reordering your enum constants changes iteration order — one more reason never to persist ordinal().
ordinal()
11
Null rules. EnumSet rejects null entirely. EnumMap rejects a null key and allows a null value.
EnumSetEnumMap
12
And the 64-constant boundary, if you are asked: up to 64 constants EnumSet uses a single long (RegularEnumSet); beyond that a long[] (JumboEnumSet). Both are O(1).
EnumSetlongRegularEnumSetlong[]JumboEnumSet
13
What the interviewer is probing.1. "Why are these faster than HashSet and HashMap?" Probing: the implementation. Stalls: "They are optimised." Moves up: EnumSet is a bit vector and EnumMap an array indexed by ordinal — no hashing, no collisions, no boxing.
14
2. "What should you use instead of an int bitmask for flags?" Probing: the modern replacement. Stalls: "Bitmasks are fine." Moves up: EnumSet.of(READ, WRITE) — as compact, type-safe, printable, and it cannot be passed a meaningless value.
15
3. "What order does iteration follow?" Probing: the ordering guarantee. Stalls: "Insertion order." Moves up: declaration order of the enum — which is another reason reordering constants is risky.
16
4. "Which factory methods are worth knowing?" Probing: the API. Stalls: "Just of." *Moves up:* allOf, noneOf, range and complementOf — none of which have an equivalent in the general collections.