【Java必修课】HashMap性能很好?问过我EnumMap没
2019-11-07 22:01
1856 查看
1 简介
我们知道
Map只是一个接口,它有多种实现,Java中最常用的是
HashMap了。而本文想讲述的是另一个实现:
EnumMap。它是枚举类型的
Map,要求它的Key值都必须是枚举型的。
2 创建你的EnumMap
既然是关于枚举类型的Map,我们先创建一个枚举,以便后续使用:
public enum Directions { NORTH, SOUTH, EAST, WEST }
2.1 创建EnumMap的三种方法
JDK提供的创建
EnumMap的方法有三种,代码如下:
//new EnumMap EnumMap<Direction, String> enumMap = new EnumMap<>(Direction.class); enumMap.put(Direction.EAST, "东"); enumMap.put(Direction.SOUTH, "南"); //从EnumMap复制 EnumMap<Direction, String> enumMapCopyEnumMap = new EnumMap<>(enumMap); assertEquals(enumMap, enumMapCopyEnumMap); //从Map复制 Map<Direction, String> hashMap = Maps.newHashMap(); hashMap.put(Direction.EAST, "东"); hashMap.put(Direction.SOUTH, "南"); EnumMap<Direction, String> enumMapCopyHashMap = new EnumMap<>(hashMap); assertEquals(enumMap, enumMapCopyHashMap);
(1) 使用
new EnumMap()
方法时,与HashMap
不同,它必须传入一个枚举的类型才能创建对象;(2) 从
EnumMap
复制,这时传入的参数为EnumMap
;(3) 从
Map
复制,传入的参数为Map
,但要求Key的类型必须是枚举型。
2.2 聪明的Guava
其实可以综合上面三种情况,实际就是两种方法:
(1) 使用
new EnumMap(Class<K> keyType)
(2) 使用
new EnumMap(Map<K, ? extends V> m)
聪明的
Guava就只提供了这两种方法,如下:
//使用Guava创建 EnumMap<Direction, String> enumMapGuava = Maps.newEnumMap(Direction.class); enumMapGuava.put(Direction.SOUTH, "南"); assertEquals(1, enumMapGuava.size()); enumMapGuava = Maps.newEnumMap(enumMap); assertEquals(enumMap, enumMapGuava);
3 基本操作
提供的方法与Map当然是一样的,操作十分方便,代码如下:
@Test public void operations() { EnumMap<Direction, String> map = Maps.newEnumMap(Direction.class); //增加 map.put(Direction.EAST, "东"); map.put(Direction.SOUTH, "南"); map.put(Direction.WEST, "西"); //查询 assertTrue(map.containsKey(Direction.EAST)); assertFalse(map.containsKey(Direction.NORTH)); //删除 map.remove(Direction.EAST); assertFalse(map.containsKey(Direction.EAST)); assertFalse(map.remove(Direction.WEST, "北")); assertTrue(map.remove(Direction.WEST, "西")); //清空 map.clear(); assertEquals(0, map.size()); }
需要特别指出的是删除方法,可以传入Key和Value两个参数,
map.remove(Direction.WEST, "西")当键值对匹配时,则可以删除成功;
map.remove(Direction.WEST, "北")匹配失败,则不会删除。
4 集合视图
4.1 有序性
与Map接口提供的功能一样,
EnumMap也能返回它的所有Values、Keys和Entry等。但与
HashMap不同的是,
EnumMap返回的视图是有序的,这个顺序不是插入的顺序,而是枚举定义的顺序。代码如下:
EnumMap<Direction, String> map = Maps.newEnumMap(Direction.class); map.put(Direction.EAST, "东"); map.put(Direction.SOUTH, "南"); map.put(Direction.WEST, "西"); map.put(Direction.NORTH, "北"); //返回所有Value Collection<String> values = map.values(); values.forEach(System.out::println); //返回所有Key Set<Direction> keySet = map.keySet(); keySet.forEach(System.out::println); //返回所有<Key,Value> Set<Map.Entry<Direction, String>> entrySet = map.entrySet(); entrySet.forEach(entry -> { System.out.println(entry.getKey() + ":" + entry.getValue()); });
输出的结果如下:
北 南 东 西 NORTH SOUTH EAST WEST NORTH:北 SOUTH:南 EAST:东 WEST:西
这个顺序与我们定义枚举的顺序确实是一样的,而与添加的顺序无关。
4.2 联动性
除了有序性之外,
EnumMap返回的集合视图还有一点不同就是联动性,即牵一发而动全身。改变其中一个,另外的也跟着变了。看代码一下就明白了:
//Values、keySet、entrySet改变会影响其它 values.remove("东"); assertEquals(3, map.size()); assertEquals(3, keySet.size()); assertEquals(3, entrySet.size()); keySet.remove(Direction.WEST); assertEquals(2, map.size()); assertEquals(2, values.size()); assertEquals(2, entrySet.size()); entrySet.removeIf(entry -> Objects.equals(entry.getValue(), "北")); assertEquals(1, map.size()); assertEquals(1, keySet.size()); assertEquals(1, values.size()); //Map的改变会影响其它视图 map.clear(); assertEquals(0, values.size()); assertEquals(0, keySet.size()); assertEquals(0, entrySet.size());
5 性能
性能是我们选择
EnumMap的主要原因之一,那为何它性能会比优秀的
HashMap还要好呢?通过看源码可以得知:
(1)底层是通过两个数组来存放数据的,一个放Keys,一个放Values;
(2)因为Key值是枚举类型,即一开始就确定了元素个数,所以在创建一个
EnumMap的时候,存放数据的数组就已经确定了大小,不用考虑后续扩容带来的性能问题。
(3)枚举本身就是固定顺序的,可以通过
Enum.ordinal()方法获得顺序,这个便可以作为查询与插入的索引,而不用计算
HashCode,性能也会比较快。这个顺序也就是数组下标。这也是
EnumMap的集合视图都是有序的原因。
(4)因为大小固定,则不用考虑加载因子,也不会有哈希冲突的问题,空间复杂度小。
6 结论
本文介绍了
EnumMap作为一个
Map的特殊实现的创建、使用、集合视图和性能分析,发现它的确是有过人之处的。当我们的Key值是枚举时,不妨可以试一试
EnumMap,性能会更好哦。
欢迎关注公众号<南瓜慢说>,将持续为你更新...
多读书,多分享;多写作,多整理。
相关文章推荐
- Java HashMap遍历方式性能探讨
- Java里多个Map的性能比較(TreeMap、HashMap、ConcurrentSkipListMap)
- Java 8 中 HashMap 的性能提升
- Java 8中HashMap的性能提升
- Java中的集合Map、HashMap、Hashtable、Properties、SortedMap、TreeMap、WeakHashMap、IdentityHashMap、EnumMap(五)
- java学习笔记之WeakHashMap 、IdentityHashMap、EnumMap
- Java 8 中 HashMap 的性能提升
- Java HashMap遍历实践,看看不同方式的性能如何
- Java HashMap提高性能和原理
- Java HashMap 两种遍历方法性能比较
- Java HashMap三种循环遍历方式及其性能对比实例分析
- Java集合之WeakHashMap、IdentityHashMap、EnumMap介绍
- Java里多个Map的性能比较(TreeMap、HashMap、ConcurrentSkipListMap)
- Java中Map的其他类型(WeakHashMap-IdentityHashMap-EnumMap)
- java8 HashMap 性能质疑
- 牛客网Java刷题知识点之HashMap的实现原理、HashMap的存储结构、HashMap在JDK1.6、JDK1.7、JDK1.8之间的差异以及带来的性能影响
- [Java] 多个Map的性能比较(TreeMap、HashMap、ConcurrentSkipListMap)
- Java中的HashMap和ConcurrentHashMap的并发性能测试
- Java HashMap 遍历方式性能探讨
- Java HashMap 遍历方式性能探讨