EnumSet & EnumMap in Java
Fast, compact collections keyed by enums.
Collections made for enums
**EnumSet and EnumMap** are collections specialised for enum keys. Create sets with EnumSet.of(...), allOf(X.class), noneOf(X.class) or range(A, C). An EnumMap needs the enum's Class: new EnumMap<>(Day.class). Neither allows null elements or keys.
var weekend = EnumSet.of(Day.SAT, Day.SUN);
var hours = new EnumMap<Day, Integer>(Day.class);
hours.put(Day.MON, 8);Under the hood: bits and arrays
Each constant has an ordinal, so an EnumSet is just a bit vector: bit 0 for the first constant, bit 1 for the next… With up to 64 constants that's a single long — add and contains are one bit operation. No hashing, no node objects. An EnumMap is an array indexed by ordinal.
Insertion order?
What does this print?
enum Day { MON, TUE, WED, THU, FRI }
void main() {
var s = EnumSet.of(Day.THU, Day.TUE);
s.add(Day.MON);
System.out.println(s);
}[THU, TUE, MON][MON, TUE, THU][TUE, THU, MON]
Show the answer
Iteration walks the bits from lowest to highest, so an EnumSet always iterates in declaration (ordinal) order, no matter what order you added things.
Is the end included?
EnumSet.range(Day.TUE, Day.THU) — does the result contain THU?
Think about it, then reveal the answer
Yes. **range includes both endpoints**: [TUE, WED, THU].
EnumMap has the same rule
An EnumMap also iterates keys in declaration order, and shows only keys that are present. merge(L, 1, Integer::sum) adds 1 to L's existing value. So this prints {S=5, L=3} — S first, even though L went in first.
enum Size { S, M, L }
Map<Size, Integer> m = new EnumMap<>(Size.class);
m.put(Size.L, 2);
m.put(Size.S, 5);
m.merge(Size.L, 1, Integer::sum);
// {S=5, L=3}Flags and schedules
User permissions as EnumSet<Permission>, feature flags, or opening hours as EnumMap<DayOfWeek, Hours> (DayOfWeek is a java.time enum). They're faster and smaller than HashSet/HashMap, and their predictable order makes logs and tests stable.
Key takeaways
- EnumSet.of(A, B), allOf(X.class), noneOf(X.class), range(A, C)
- new EnumMap<>(Day.class) needs the enum's Class
- Iteration always follows declaration order
- Null elements or keys are not allowed
💡 A row of labelled light switches: each constant has its own fixed slot that is either on or off.
Ask an EnumSet for its real class and you get RegularEnumSet — one long of bits. Enums with more than 64 constants get a JumboEnumSet, backed by an array of longs.
Practice questions
What does this print?
enum Day { MON, TUE, WED, THU, FRI }
void main() {
var set = EnumSet.of(Day.FRI, Day.MON);
set.add(Day.WED);
System.out.println(set);
}- [MON, WED, FRI]
- [FRI, MON, WED]
- [FRI, WED, MON]
- [WED, FRI, MON]
Check your answer
[MON, WED, FRI]. Membership is stored as bits indexed by ordinal, so iteration walks MON → FRI in declaration order.
What does this print?
enum Day { MON, TUE, WED, THU, FRI }
void main() {
var mid = EnumSet.range(Day.TUE, Day.THU);
System.out.println(mid);
}- [TUE, WED, THU]
- [TUE, WED]
- [WED]
- [TUE, THU]
Check your answer
[TUE, WED, THU]. EnumSet.range includes both endpoints, so you get TUE, WED and THU.