A Guide to EnumMap

1. Overview

EnumMap is a Map implementation that exclusively takes Enum as its keys.

In this tutorial, we’ll discuss its properties, common use cases and when we should use it.

2. Project Setup

Imagine a simple requirement where we need to map days of the week with the sport we play on that day:

Monday     Soccer                         
Tuesday    Basketball                     
Wednesday  Hiking                         
Thursday   Karate

For this, we could use an enum:

public enum DayOfWeek {
    MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}

Which we’ll see soon will be the key for our map.

3. Creation

To start exploring EnumMap, first we’ll need to instantiate one:

EnumMap<DayOfWeek, String> activityMap = new EnumMap<>(DayOfWeek.class);
activityMap.put(DayOfWeek.MONDAY, "Soccer");

And here is our first difference to something more common, like HashMap. Note that with HashMap, the type parameterization is sufficient, meaning we can get away with new HashMap<>(). However, EnumMap requires the key type in the constructor.

3.1. EnumMap Copy Constructor

EnumMap also ships with two copy constructors. The first takes another EnumMap:

EnumMap<DayOfWeek, String> activityMap = new EnumMap<>(DayOfWeek.class);
activityMap.put(DayOfWeek.MONDAY, "Soccer");
activityMap.put(DayOfWeek.TUESDAY, "Basketball");

EnumMap<DayOfWeek, String> activityMapCopy = new EnumMap<>(dayMap);
assertThat(activityMapCopy.size()).isEqualTo(2);
assertThat(activityMapCopy.get(DayOfWeek.MONDAY)).isEqualTo("Soccer");
assertThat(activityMapCopy.get(DayOfWeek.TUESDAY)).isEqualTo("Basketball");

3.2. Map Copy Constructor

Or, if we have a non-empty Map whose key is an enum, then we can do that, too:

Map<DayOfWeek, String> ordinaryMap = new HashMap();
ordinaryMap.put(DayOfWeek.MONDAY, "Soccer");

EnumMap enumMap = new EnumMap(ordinaryMap);
assertThat(enumMap.size()).isEqualTo(1);
assertThat(enumMap.get(DayOfWeek.MONDAY)).isEqualTo("Soccer");

Note that the map must be non-empty so that EnumMap can determine the key type from an existing entry.

If the specified map contains more than one enum type, the constructor will throw ClassCastException.

4. Adding and Retrieving Elements

After instantiating an EnumMap, we can add our sport using the put() method:

activityMap.put(DayOfWeek.MONDAY, "Soccer");

And to retrieve it, we can use get():

assertThat(clubMap.get(DayOfWeek.MONDAY)).isEqualTo("Soccer");

5. Checking for Elements

To check if we have a mapping defined for a particular day, we use containsKey():

activityMap.put(DayOfWeek.WEDNESDAY, "Hiking");
assertThat(activityMap.containsKey(DayOfWeek.WEDNESDAY)).isTrue();

And, to check if a particular sport is mapped to any key we use containsValue():

assertThat(activityMap.containsValue("Hiking")).isTrue();

5.1. null as Value

Now, null is a semantically valid value for EnumMap.

Let’s associate null with “doing nothing”, and map it to Saturday:

assertThat(activityMap.containsKey(DayOfWeek.SATURDAY)).isFalse();
assertThat(activityMap.containsValue(null)).isFalse();
activityMap.put(DayOfWeek.SATURDAY, null);
assertThat(activityMap.containsKey(DayOfWeek.SATURDAY)).isTrue();
assertThat(activityMap.containsValue(null)).isTrue();

6. Removing Elements

In order to unmap a particular day, we simply remove() it:

activityMap.put(DayOfWeek.MONDAY, "Soccer");
assertThat(activityMap.remove(DayOfWeek.MONDAY)).isEqualTo("Soccer");
assertThat(activityMap.containsKey(DayOfWeek.MONDAY)).isFalse();

As we can observe, remove(key) returns the previous value associated with the key, or null if there was no mapping for the key.

We can also choose to unmap a particular day only if that day is mapped to a particular activity:

activityMap.put(DayOfWeek.Monday, "Soccer");
assertThat(activityMap.remove(DayOfWeek.Monday, "Hiking")).isEqualTo(false);
assertThat(activityMap.remove(DayOfWeek.Monday, "Soccer")).isEqualTo(true);

remove(key, value) removes the entry for the specified key only if the key is currently mapped to the specified value.

7. Collection Views

Just like with ordinary maps, with any EnumMap, we can have 3 different views or sub-collections.

First, let’s create a new map of our activities:

EnumMap<DayOfWeek, String> activityMap = new EnumMap(DayOfWeek.class);
activityMap.put(DayOfWeek.THURSDAY, "Karate");
activityMap.put(DayOfWeek.WEDNESDAY, "Hiking");
activityMap.put(DayOfWeek.MONDAY, "Soccer");

7.1. values

The first view of our activity map is values() which, as the name suggests, returns all the values in the map:

Collection values = dayMap.values();
assertThat(values)
  .containsExactly("Soccer", "Hiking", "Karate");

Note here that EnumMap is an ordered map. It uses the order of the DayOfWeek enum to determine the order of the entries.

7.2. keySet

Similarly, keySet() returns a collection of the keys, again in enum order:

Set keys = dayMap.keySet();
assertThat(keys)
        .containsExactly(DayOfWeek.MONDAY, DayOfWeek.WEDNESDAY, DayOfWeek.SATURDAY);

7.3. entrySet

Lastly, entrySet() returns the mapping in pairs of key and value:

assertThat(dayMap.entrySet())
    .containsExactly(
        new SimpleEntry(DayOfWeek.MONDAY, "Soccer"),
        new SimpleEntry(DayOfWeek.WEDNESDAY, "Hiking"),
        new SimpleEntry(DayOfWeek.THURSDAY, "Karate")
    );

Ordering in a map can certainly come in handy, and we go into more depth in our tutorial that compares TreeMap to HashMap.

7.4. Mutability

Now, remember that any changes we make in the original activity map will be reflected in any of its views:

activityMap.put(DayOfWeek.TUESDAY, "Basketball");
assertThat(values)
    .containsExactly("Soccer", "Basketball", "Hiking", "Karate");

And vice-versa; any changes we make the sub-views will be reflected in the original activity map:

values.remove("Hiking");
assertThat(activityMap.containsKey(DayOfWeek.WEDNESDAY)).isFalse();
assertThat(activityMap.size()).isEqualTo(3);

Per EnumMap‘s contract with Map interface, the sub-views are backed by the original map.

8. When to Use EnumMap

8.1. Performance

Using Enum as key makes it possible to do some extra performance optimization, like a quicker hash computation since all possible keys are known in advance.

The simplicity of having enum as key means EnumMap only need to be backed up by a plain old Java Array with very simple logic for storage and retrieval. On the other hand, generic Map implementations need to cater for concerns related to having a generic object as its key. For example, HashMap needs a complex data structure and a considerably more complex storing and retrieval logic to cater for the possibility of hash collision.

8.2. Functionality

Also, as we saw, EnumMap is an ordered map, in that its views will iterate in enum order. To get similar behavior for more complex scenarios, we can look at TreeMap or LinkedHashMap.

9. Conclusion

In this article, we’ve explored the EnumMap implementation of the Map interface. When working with Enum as a key, EnumMap can come in handy.

The full source code for all the examples used in this tutorial can be found in the GitHub project.

Related posts:

The Difference Between Collection.stream().forEach() and Collection.forEach()
Java Program to Use Above Below Primitive to Test Whether Two Lines Intersect
Phương thức tham chiếu trong Java 8 – Method References
Java Program to Implement Knapsack Algorithm
Java Program to Implement Heap Sort Using Library Functions
Rest Web service: Filter và Interceptor với Jersey 2.x (P1)
Java Program to Implement Hash Tables with Quadratic Probing
Spring @RequestParam Annotation
Generate Spring Boot REST Client with Swagger
Java Program to Find Second Smallest of n Elements with Given Complexity Constraint
Using the Map.Entry Java Class
Java Program to Implement the Program Used in grep/egrep/fgrep
Hướng dẫn Java Design Pattern – Dependency Injection
Find the Registered Spring Security Filters
Allow user:password in URL
Adding a Newline Character to a String in Java
Guide to the Synchronized Keyword in Java
Introduction to Java 8 Streams
How to Read a Large File Efficiently with Java
Java 8 – Powerful Comparison with Lambdas
Converting a Stack Trace to a String in Java
Java Program to Implement Dijkstra’s Algorithm using Set
Java Program to Implement the Binary Counting Method to Generate Subsets of a Set
Java Program to Generate a Random UnDirected Graph for a Given Number of Edges
Java Program to Implement Strassen Algorithm
Using Custom Banners in Spring Boot
Read an Outlook MSG file
Check If a String Is Numeric in Java
Java Streams vs Vavr Streams
Spring Boot - Code Structure
Java Program to Find a Good Feedback Edge Set in a Graph
Java Program to implement Circular Buffer