skip to content

What is EnumMap, how does it work internally, and when should you choose it over HashMap?

level: middleimportance: should knowfreq 58%

answer

  1. array indexed by ordinal -> O(1), no hashing
  2. construct with the enum Class: new EnumMap<>(E.class)
  3. keys iterate in declaration order
  4. null key forbidden, null values allowed
  5. use it whenever keys are an enum

basics

~20 s

EnumMap is a Map whose keys are constants of one enum type. Internally it is just an array indexed by each key's ordinal, so lookups and inserts are very fast and memory-light. Create it with new EnumMap<>(MyEnum.class). Keys iterate in declaration order.

solid answer

~50 s

EnumMap is a specialized Map implementation where the keys must all be constants of a single enum type. Internally it is backed by a plain array sized to the number of enum constants; a key's ordinal is the array index. That means get/put are direct array accesses — no hashing, no collisions, no bucket nodes — so it is faster and far more compact than HashMap for enum keys. You construct it with the enum's Class object (new EnumMap<>(Color.class)) or by copying another map. Keys are iterated in the enum's natural (declaration) order, which is often a useful, deterministic property. It permits null values but not a null key, and it is not thread-safe. It is the idiomatic choice whenever you map from an enum to something — for example a per-status counter or per-type handler.

code

java · 8 lines
java
enum Status { NEW, ACTIVE, CLOSED }

EnumMap<Status, Integer> counts = new EnumMap<>(Status.class);
for (Order o : orders) {
    counts.merge(o.status(), 1, Integer::sum);
}
// iterates NEW, ACTIVE, CLOSED in declaration order
counts.forEach((s, n) -> System.out.println(s + ": " + n));

go deeper

for a junior

Knows EnumMap is a Map with enum keys, created via new EnumMap<>(E.class).

for a middle

Explains the ordinal-indexed array backing, the speed/memory and ordering benefits over HashMap, and the null-key vs null-value rules.

for a senior

Justifies EnumMap over both HashMap and hand-rolled ordinal arrays, knows the absent-vs-null-value sentinel detail and thread-safety limits, and picks it for enum-keyed maps by default.

for a principal

Standardizes EnumMap for enum-keyed dispatch/config across a codebase, considers immutability/defensive copies at API boundaries, and reasons about when its constant-factor gains are worth caring about versus clarity.

## Background: Map and enum A **Map** associates **keys** with **values** (`java.util.Map`); each key appears once. The common implementation, **HashMap**, computes each key's `hashCode`, places the entry in a bucket, and uses `equals` to find it again. An **enum** is a type with a fixed set of named constants, each with an **ordinal** — its zero-based position in declaration order. ## What EnumMap is `EnumMap<K extends Enum<K>, V>` is a `Map` whose **keys must be constants of one enum type**. Because that key space is fixed and small, the JDK can store the values in a **plain array** whose length equals the number of enum constants. The value for key `k` lives at index `k.ordinal()`. So: - `get(k)` = read `array[k.ordinal()]`. - `put(k, v)` = write `array[k.ordinal()] = v`. There is **no hashing, no collision handling, and no per-entry node object** — just direct array indexing. ## Construction Unlike HashMap, EnumMap needs to know the key type up front (to size the array and validate keys), so you pass the enum's `Class`: ```java enum Color { RED, GREEN, BLUE } EnumMap<Color, Integer> counts = new EnumMap<>(Color.class); counts.put(Color.RED, 1); int r = counts.get(Color.RED); // 1 ``` You can also copy from an existing `EnumMap` or any non-empty `Map` with enum keys. ## Why it beats HashMap for enum keys - **Speed:** array indexing by ordinal is about as fast as Java data access gets; no `hashCode`/`equals` work, no bucket walking. - **Memory:** one array plus the values, versus HashMap's bucket array and a `Node` per entry. - **Deterministic order:** iterating keys (or `entrySet`) yields the enum's **declaration order**, which is stable and meaningful — HashMap order is effectively arbitrary. - **Type safety:** keys are constrained to the one enum type. ## Null rules and thread-safety - A **null key** is rejected (`NullPointerException`) — there is no ordinal for null. - **Null values are allowed.** Internally EnumMap distinguishes "absent" from "present with null value" using a sentinel, so `containsKey` is accurate even for null values. - It is **not thread-safe**; wrap with `Collections.synchronizedMap(...)` for shared mutable access. ## When to choose it Use EnumMap whenever the keys are an enum: a count per `OrderStatus`, a strategy/handler per `EventType`, configuration per `Environment`, etc. It gives HashMap-like ergonomics with array-like performance and deterministic ordering. The main reason to use HashMap instead is when keys are not all from one enum, or you specifically need a different iteration order or a concurrent map (`ConcurrentHashMap`). ## Relationship to ordinal-indexed arrays A tempting micro-optimization is `V[] byOrdinal = new V[Enum.values().length]` indexed by `ordinal()`. EnumMap gives you that performance **plus** the full `Map` API, null-value correctness, bounds/key validation, and readability — so prefer EnumMap over hand-rolled ordinal arrays.

  • Why must you pass the enum's Class to the EnumMap constructor?
    EnumMap needs the key type at construction to size its internal value array to the number of constants and to validate that keys belong to that enum; unlike HashMap it cannot infer this lazily from the first key.
  • Does EnumMap allow null keys or null values?
    Null values are allowed (it uses a sentinel to tell 'absent' from 'present-null'); a null key throws NullPointerException because there is no ordinal for null.

Like numbered mailboxes in a lobby: each enum key has a fixed slot number (its ordinal), so you go straight to its box instead of searching a directory.

saying these in an interview costs you the question

  • Thinking EnumMap uses hashing/buckets like HashMap — it uses an ordinal-indexed array.
  • Trying to put a null key (throws NPE).
  • Assuming HashMap iteration order; EnumMap is declaration order.
  • Hand-rolling an ordinal-indexed array instead of using EnumMap and losing the Map API and null-value correctness.

context