A Guide to EnumMap – EnumMap指南

最后修改: 2018年 11月 2日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

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

EnumMap是一个Map实现,它只接受Enum作为其键。

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

在本教程中,我们将讨论它的属性、常见的使用情况以及我们应该何时使用它。

2. Project Setup

2.项目设置

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

3.创造

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

要开始探索EnumMap,首先我们需要实例化一个。

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.

这里是我们与更常见的东西的第一个区别,比如HashMap。请注意,对于HashMap,类型参数化是足够的,这意味着我们可以用new HashMap<>()来解决。然而,EnumMap要求在构造函数中提供键类型

3.1. EnumMap Copy Constructor

3.1.EnumMap复制构造函数

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

EnumMap也有两个复制构造函数。第一个构造函数需要另一个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

3.2.Map Copy构造函数

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

或者,如果我们有一个非空的Map,其键是一个枚举,那么我们也可以这样做:

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.

注意,该地图必须是非空的,以便EnumMap能够从现有条目中确定键类型。

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

如果指定的映射包含一个以上的枚举类型,构造函数将抛出ClassCastException

4. Adding and Retrieving Elements

4.添加和检索元素

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

在实例化一个EnumMap之后,我们可以使用put()方法添加我们的运动。

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

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

而要检索它,我们可以使用get()

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

5. Checking for Elements

5.检查元素

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

为了检查我们是否为某一天定义了一个映射,我们使用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():

而且,为了检查某项运动是否被映射到任何键上,我们使用containsValue()

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

5.1. null as Value

5.1.null为值

Now, null is a semantically valid value for EnumMap.

现在,nullEnumMap的一个语义上有效的值。

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

让我们把null与 “无所作为 “联系起来,并把它映射到星期六。

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

6.移除元素

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

为了取消某一天的映射,我们只需remove()它。

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.

正如我们所观察到的,remove(key)返回与键相关的先前值,或者null如果没有键的映射。

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.

remove(key, value) 只有当键当前被映射到指定的值时,才会删除指定键的条目。

7. Collection Views

7.收集意见

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

就像普通地图一样,对于任何EnumMap,我们可以有3个不同的视图或子集合。

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

7.1.

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

我们活动地图的第一个视图是values(),顾名思义,它返回地图中的所有值。

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.

请注意,EnumMap是一个有序的地图。它使用DayOfWeekenum的顺序来决定条目的顺序。

7.2. keySet

7.2.keySet

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

类似地,keySet()返回一个键的集合,同样是按照枚举的顺序。

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

7.3. entrySet

7.3.entrySet

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

最后,entrySet()以键和值对的形式返回映射。

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.

在地图中排序当然可以派上用场,我们在比较TreeMap和HashMap的教程中进行了更深入的介绍。

7.4. Mutability

7.4.可变性

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.

根据EnumMapMap接口的契约,子视图是由原始地图支持的。

8. When to Use EnumMap

8.何时使用EnumMap

8.1. Performance

8.1.业绩

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.

使用Enum作为键,可以做一些额外的性能优化,比如更快的哈希计算,因为所有可能的键都是事先知道的。

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.

enum作为键的简单性意味着EnumMap只需要由一个普通的旧JavaArray来支持,其存储和检索的逻辑非常简单。另一方面,通用的Map实现需要照顾到与将通用对象作为其键有关的问题。例如,HashMap 需要一个复杂的数据结构和一个相当复杂的存储和检索逻辑来应对哈希碰撞的可能性。

8.2. Functionality

8.2.功能性

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.

另外,正如我们所看到的,EnumMap是一个有序的地图,因为它的视图将以枚举的顺序进行迭代。为了在更复杂的情况下获得类似的行为,我们可以看看TreeMapLinkedHashMap

9. Conclusion

9.结语

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.

在这篇文章中,我们已经探讨了EnumMap接口的Map实现。当使用Enum作为一个键时,EnumMap可以派上用场。

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

本教程中使用的所有示例的完整源代码可以在GitHub项目中找到。