🪆 Enums, Records & Nested Types · Intermediate

EnumSet & EnumMap in Java

Fast, compact collections keyed by enums.

🧩 The mysteryAdd FRI, then MON, then WED to a set. Print it: [MON, WED, FRI]. You never sorted anything. Who rearranged your data?

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.

🔮 Predict it

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);
}
  1. [THU, TUE, MON]
  2. [MON, TUE, THU]
  3. [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.

🤔 Think first

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].

⚠️ The trap

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}
💼 In the real world

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

  1. EnumSet.of(A, B), allOf(X.class), noneOf(X.class), range(A, C)
  2. new EnumMap<>(Day.class) needs the enum's Class
  3. Iteration always follows declaration order
  4. 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.

🤯 Did you know?

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);
}
  1. [MON, WED, FRI]
  2. [FRI, MON, WED]
  3. [FRI, WED, MON]
  4. [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);
}
  1. [TUE, WED, THU]
  2. [TUE, WED]
  3. [WED]
  4. [TUE, THU]
Check your answer

[TUE, WED, THU]. EnumSet.range includes both endpoints, so you get TUE, WED and THU.

Next: the shortest, safest singleton in Java is… a one-constant enum. Why can't reflection break it?