EnumMap
Sometimes we use enum
values as keys for lookups in a hash table. With HashMap
, checking for enum
keys is slower than ideal. It is not optimized for enums.
This class
has special optimizations for hashing enums. It performs faster than an equivalent HashMap
. I provide a simple benchmark.
We first create an EnumMap
with custom enum
(Importance) keys. Please notice how we specify Importance.class
as the argument to EnumMap
—this is unlike HashMap
's syntax.
EnumMap
with put. The new key is the first argument. The new value is the second.Get()
fetches a value from the map based on a key. Here we use constant enum
values, but variables also work.import java.util.EnumMap; public class Program { enum Importance { Low, Medium, High, Critical } public static void main(String[] args) { // Create an EnumMap. EnumMap<Importance, String> e = new EnumMap<>(Importance.class); e.put(Importance.Low, "=Low"); e.put(Importance.High, "=High"); // Get values from the map. String value1 = e.get(Importance.Low); String value2 = e.get(Importance.High); System.out.println(value1); System.out.println(value2); } }=Low =High
ContainsKey
This is an important method on EnumMap
. It receives one argument, of the specified enum
's type. It returns true, if found, and false, if the key is not present.
import java.util.EnumMap; public class Program { enum Importance { Low, Medium, High, Critical } public static void main(String[] args) { EnumMap<Importance, String> e = new EnumMap<>(Importance.class); e.put(Importance.Critical, "=Critical"); e.put(Importance.High, "=High"); // This is not present. System.out.println(e.containsKey(Importance.Low)); // This is present in the EnumMap. if (e.containsKey(Importance.Critical)) { System.out.println(1); } } }false 1
KeySet
gets keysThe keySet
method returns a Set of the EnumMap
's keys. We can loop over the set with a for
-loop. As with HashMap
, we can convert this set into an ArrayList
.
import java.util.EnumMap; import java.util.Set; public class Program { enum Size { Small, Normal, Large } public static void main(String[] args) { EnumMap<Size, Integer> e = new EnumMap<>(Size.class); e.put(Size.Small, 10); e.put(Size.Normal, 20); // Get keys and loop over them. Set<Size> set = e.keySet(); for (Size s : set) { System.out.println(s); } } }Small Normal
EnumMap
The EnumMap
is faster for lookups than a HashMap
with enum
keys. In this benchmark, I found EnumMap
is a bit less than twice as fast on simple lookups.
EnumMap
to look up an Enum
defined in the program.HashMap
. We call containsKey
on an enum
.enum
keys in a HashMap
(or other collection) will benefit from EnumMap
. The benefits are clear.import java.util.HashMap; import java.util.EnumMap; public class Program { enum Importance { Low, Medium, High, Critical } public static void main(String[] args) throws Exception { EnumMap<Importance, String> e = new EnumMap<>(Importance.class); e.put(Importance.Low, "=Low"); e.put(Importance.High, "=High"); HashMap<Importance, String> h = new HashMap<>(); h.put(Importance.Low, "=Low"); h.put(Importance.High, "=High"); long t1 = System.currentTimeMillis(); // Version 1: check EnumMap. for (int i = 0; i < 10000000; i++) { if (!e.containsKey(Importance.Low)) { throw new Exception(); } } long t2 = System.currentTimeMillis(); // Version 2: check HashMap. for (int i = 0; i < 10000000; i++) { if (!h.containsKey(Importance.Low)) { throw new Exception(); } } long t3 = System.currentTimeMillis(); // ... Times. System.out.println(t2 - t1); System.out.println(t3 - t2); } } 85 ms, EnumMap lookup 144 ms, HashMap lookup
Some performance optimizations are difficult. They require extensive changes to a program score. But EnumMap
is the opposite: we can easily replace a HashMap
for an EnumMap
.
And the benefits are clear. Lookups based on enum
keys are consistently faster. The code is optimized. In programs with enum
keys, EnumMap
is a definite win.