【Java必修课】HashMap性能很好?问过我EnumMap没
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性能很好?问过我EnumMap没的更多相关文章
- java反射机制性能优化
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.uti ...
- JDK1.8源码(七)——java.util.HashMap 类
本篇博客我们来介绍在 JDK1.8 中 HashMap 的源码实现,这也是最常用的一个集合.但是在介绍 HashMap 之前,我们先介绍什么是 Hash表. 1.哈希表 Hash表也称为散列表,也有直 ...
- Java面试& HashMap实现原理分析
1. HashMap的数据结构 数据结构中有数组和链表来实现对数据的存储,但这两者基本上是两个极端. 数组 数组存储区间是连续的,占用内存严重,故空间复杂的很大.但数组的二分查找时间复杂度小,为O( ...
- 关于Android中ArrayMap/SparseArray比HashMap性能好的深入研究
由于网上有朋友对于这个问题已经有了很详细的研究,所以我就不班门弄斧了: 转载于:http://android-performance.com/android/2014/02/10/android-sp ...
- Java之HashMap在多线程情况下导致死循环的问题
PS:不得不说Java编程思想这本书是真心强大.. 学习内容: 1.HashMap<K,V>在多线程的情况下出现的死循环现象 当初学Java的时候只是知道HashMap<K,V& ...
- java中HashMap的用法
重点介绍HashMap.首先介绍一下什么是Map.在数组中我们是通过数组下标来对其内容索引的,而在Map中我们通过对象来对对象进行索引,用来索引的对象叫做key,其对应的对象叫做value.在下文中会 ...
- 《转》Java中HashMap详解
HashMap 和 HashSet 是 Java Collection Framework 的两个重要成员,其中 HashMap 是 Map 接口的常用实现类,HashSet 是 Set 接口的常用实 ...
- Java中HashMap和TreeMap的区别深入理解
首先介绍一下什么是Map.在数组中我们是通过数组下标来对其内容索引的,而在Map中我们通过对象来对对象进行索引,用来索引的对象叫做key,其对应的对象叫做value.这就是我们平时说的键值对. Has ...
- Java学习----HashMap原理
1.HashMap的数据结构 数组的特点是:寻址容易,插入和删除困难:而链表的特点是:寻址困难,插入和删除容易.那么我们能不能综合两者的特性,做出一种寻址容易,插入删除也容易的数据结构?答案是肯定的, ...
随机推荐
- AOP框架Dora.Interception 3.0 [1]: 编程体验
.NET Core正式发布之后,我为.NET Core度身定制的AOP框架Dora.Interception也升级到3.0.这个版本除了升级底层类库(.NET Standard 2.1)之外,我还对它 ...
- Docker 学习笔记之 核心概念
Docker核心概念: Docker Daemon Docker Container Docker Registry Docker Client 通过rest API 和Docker Daemon进程 ...
- php数字函数
is_numeric() 检查变量是否包含一个合法数字 round() 取整数,四舍五入 round(数字, 小数位) ceil() 向上取整 floor() 向下取整 range() 生成范围 ...
- 【CJOJ】为了博多
Description 做了个噩梦,梦见我的 n 把刀到60级会二次变身,变成一个 对推6图有xi点贡献,刷大阪城有yi点贡献 的刀,于是要把刀分成两队一队刷大阪城另一队推6图 . 但是有m对兄弟刀在 ...
- mac上git安装与github基本使用
目录 安装git 创建ssh key.配置git 提交本地项目到GitHub 一.安装Git MAC安装Git 首先查看电脑是否安装Git,终端输入: git 1.通过homebrew安装Git 1. ...
- Tomcat基本知识(一)
顶层架构先上一张Tomcat的顶层结构图(图A),如下: Tomcat中最顶层的容器是Server,代表着整个服务器,从上图中可以看出,一个Server可以包含至少一个Service,用于具体提供服务 ...
- 致远OA_0day批量植Cknife马一步到位
最近各位师傅都在刷这个嘛,原本的exp是上传一个test123456.jsp的命令执行的马子,不过我在试的时候发现替换成C刀一句话出错,原因未知,并且test123456.jsp如果存在的话用原来ex ...
- CTFd平台部署
学校要办ctf了,自己一个人给学校搭建踩了好多坑啊..这里记录一下吧 心累心累 这里只记录尝试成功的过程 有些尝试失败的就没贴上来 为各位搭建的时候节省一部分时间吧. ubuntu18搭建 0x01 ...
- Linux系统取证实践
目录 0x00 本课概述 0x01 用到命令 0x00 本课概述 本课时学习Linux系统下取证分析命令. 0x01 用到命令 1.top命令 2.ps命令 3.kill命令 4.linux系统日 ...
- [JZOJ100047] 【NOIP2017提高A组模拟7.14】基因变异
Description 21 世纪是生物学的世纪,以遗传与进化为代表的现代生物理论越来越多的 进入了我们的视野. 如同大家所熟知的,基因是遗传因子,它记录了生命的基本构造和性能. 因此生物进化与基因的 ...