Map
一、获取key和value
获取key:map.keySet(),获取map中所有的key,返回一个Set集合存储所有的键;
获取value:Map.values()或者map.entrySet()
-
Map.values(),方法用来获取 Map 集合中的所有value,将值存放在一个Set集合中
-
map.entrySet()✅,同时获取map的key和value,只需要查询一次;然后for循环key,根据key获取value
二、常用map之间的区别和使用场景
2.1. hashMap, hashtable,linkedHashMap,treeMap之间的区别
(1)hashMap: 以键值对尽心存储,线程不安全,无序,可以允许一个null键和多个null,可以通过键直接获取对应值,所以查询效率高
(2) concurrentHashMap:
(3) linkedHashMap: 它是hashmap的子集,在继承hashmap的同时添加了一个排序字段,记录插入的顺序,通过for循环可以有序的输出
(4) treemap: 它实现了sortedmap,所以可以进行集合排序输出,默认是通过key进行的升序进行排序,也可以自定义进行排序
(5) hashtable(最好不用): 它也是通过键值对进行存储,无序,但是他是线程安全的,绝大多数方法使用synchronized修饰,不允许null键和null值,一般用于多线程并发情况,但是在最新的代码中最好不使用,在单线程中使用hashmap效率快,在多线程并发下,使用ConcurrentHashMap效率更快
2.2. 使用场景
当程序是单线程,且对集合输出的排序没有确切要求时使用hashMap
当程序是多线程并发情况,并且不需要排序,最好使用ConcurrentHashMap
当程序中需要先进先出时,我们则要使用linkedHashMap
当程序中需要对于集合进行特殊化排序时,我们即可使用TreeMap
对比项 |
HashMap |
ConcurrnetHashMap |
HashTable(不用) |
---|---|---|---|
线程安全 |
非线程安全 |
线程安全 |
线程安全 |
效率 |
最高 |
高 |
低 |
键和值 |
允许为null |
允许为null |
都不允许 |
使用选择 |
普通map |
需要线程安全 |
2.3 HashMap和HashTable
- HashMap是非线程安全的,HashTable是线程安全的(内部的方法基本都经过synchronized修饰,其实是对对象加锁,锁住的都是对象整体,当Hashtable的大小增加到一定的时候,性能会急剧下降,因为迭代时需要被锁定很长的时间)
- HashMap的键和值都允许有null存在,而HashTable则都不行。
- 因为线程安全、哈希效率的问题,HashMap效率比HashTable的要高(HashTable效率低所以不怎么使用)。
- HashMap默认初始化数组的大小为16,扩容时乘2,使用位运算取得哈希,效率高于取模;jdk8之后,如果链表的长度大于8,这个单向链表就会转换为红黑树;如果链表长度小于6位,就会从红黑树转换为链表。数组扩容时,扩容的大小是原有数组的2倍;HashTable为11,扩容时为乘2加1,都是素数和奇数,这样取模哈希结果更均匀。
三、ConcurrentHashMap
3.1 线程安全
ConcurrentHashMap 的线程安全指的是:提供的原子性读写操作是线程安全的, 也就是put()、get()操作是线程安全的。即在ConcurrentHashMap的内部使用CAS保证了更新操作的原子性,在同一时间只有一个线程能够完成对值的更新。
3.2 ConcurrentHashMap为什么高效?
Hashtable低效主要是因为所有访问Hashtable的线程都争夺一把锁。如果容器有很多把锁,每一把锁控制容器中的一部分数据,那么当多个线程访问容器里的不同部分的数据时,线程之前就不会存在锁的竞争,这样就可以有效的提高并发的访问效率。这也正是ConcurrentHashMap使用的分段锁技术。将ConcurrentHashMap容器的数据分段存储,每一段数据分配一个Segment(锁),当线程占用其中一个Segment时,其他线程可正常访问其他段数据。
3.3 方法
-
put()
-
get()
-
size()
-
computeIfAbsent:Value不存在时才计算
-
computeIfPresent:Value存在时才计算
-
compute:计算并更新值
https://wizardforcel.gitbooks.io/modern-java/content/ch6.html
http://blog.tanpeng.net/2017/07/13/map-compute/
3.4 问题
1、get+put操作并非原子操作,会导致线程不安全
问题描述:https://blog.csdn.net/weixin_46539949/article/details/121114944
解决:synchronized或者computeIfAbsent
- 1、synchronized代码块锁住map(效率低 )
- 2、使用computeIfAbsent
四、HashMap
4.1方法
-
getOrDefault() 方法获取指定 key 对应对 value,如果找不到 key ,则返回设置的默认值。语法为hashmap.getOrDefault(Object key, V defaultValue)
五、ImmutableMap
可以更简洁地创建Map对象并赋值;对象创建后不可变。
5.1 特点
1.对不可靠的客户代码库来说,它使用安全,可以在未受信任的类库中安全的使用这些对象
2.线程安全的:immutable对象在多线程下安全,没有竞态条件
3.不需要支持可变性, 可以尽量节省空间和时间的开销. 所有的不可变集合实现都比可变集合更加有效的利用内存 (analysis)
4.可以被使用为一个常量,并且期望在未来也是保持不变的
5.2 使用
ImmutableMap.of("a", 1, "b", 2);
2、使用Builder类创建
Map<String,Object> immutableMap = new ImmutableMap.Builder<String,Object>() .put("k1","v1") .put("k2","v2") .build();
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话