当前位置: 首页 > ai >正文

Map 集合

Map集合体系



/*V put(K key,V value)                    添加元素V remove(Object key)                    根据键删除键值对元素void clear()                            移除所有的键值对元素boolean containsKey(Object key)         判断集合是否包含指定的键boolean containsValue(Object value)     判断集合是否包含指定的值boolean isEmpty()                       判断集合是否为空int size()                              集合的长度,也就是集合中键值对的个数
V get(Object key);
Set<K> keySet();  

 

 

Collection<V> values();

 

 Map.of(K k1, V v1, K k2, V v2, K k3, V v3) 静态方法

        该方法 是 Java 9 引入的一个静态工厂方法,用于快速创建 包含3个键值对的不可变 Map。

方法特点

  1. ​静态方法​​:属于 Map 接口,可以直接通过 Map.of() 调用
  2. ​泛型方法​​:支持任意类型的键(K)和值(V)
  3. ​参数列表​​:接受3个键值对(共6个参数)
  4. ​不可变Map​​:返回的 Map 是不可修改的  UnsupportedOperationException
  5. ​不允许null​​:键和值都不能为null,否则会抛出 NullPointerException
  6. ​不允许重复键​​:如果键重复,会抛出 IllegalArgumentException

使用示例

Map<String, Integer> ageMap = Map.of("Alice", 25,"Bob", 30,"Charlie", 28
);System.out.println(ageMap); // 输出: {Alice=25, Bob=30, Charlie=28}

注意事项

  1. 返回的 Map 是不可变的,尝试修改会抛出 UnsupportedOperationException
  2. Java 9 提供了从0到10个键值对的重载方法(Map.of()Map.of(K k1, V v1, ..., K k10, V v10)
  3. 如果需要更多元素或可变 Map,可以使用 HashMap 或其他 Map 实现类

替代方案

如果需要创建可变的 Map 或包含更多元素:

// 使用 HashMap
Map<String, Integer> mutableMap = new HashMap<>();
mutableMap.put("Alice", 25);
mutableMap.put("Bob", 30);
mutableMap.put("Charlie", 28);// 使用 Map.ofEntries 创建更多元素的不可变 Map
Map<String, Integer> largeMap = Map.ofEntries(entry("Alice", 25),entry("Bob", 30),entry("Charlie", 28),entry("David", 35)
);

这个方法为创建小型不可变 Map 提供了简洁的语法糖。

 

 Map.ofEntries() 静态方法

   Map.ofEntries() 是 Java 9 引入的另一个静态工厂方法,用于创建包含任意数量键值对的不可变 Map。与 Map.of() 方法相比,它更适合创建包含较多元素的 Map。

方法签名

static <K,V> Map<K,V> ofEntries(Map.Entry<? extends K,? extends V>... entries)

方法特点

  1. ​可变参数​​:可以接受任意数量的 Map.Entry 对象
  2. ​创建不可变Map​​:返回的 Map 是不可修改的
  3. ​不允许null​​:键和值都不能为null
  4. ​不允许重复键​​:如果键重复会抛出 IllegalArgumentException
  5. ​与 Map.Entry.entry() 配合使用​​:通常与 Map.entry() 静态方法一起使用

使用示例

import static java.util.Map.entry;Map<String, Integer> ageMap = Map.ofEntries(entry("Alice", 25),entry("Bob", 30),entry("Charlie", 28),entry("David", 35),entry("Eve", 32)
);System.out.println(ageMap);
// 输出: {Alice=25, Bob=30, Charlie=28, David=35, Eve=32}

Map.of() 的比较

特性Map.of()Map.ofEntries()
最大元素数量10个键值对无限制
语法直接键值对需要 entry() 包装
可读性少量元素时更好大量元素时更好
底层实现特殊优化类常规不可变Map实现

注意事项

  1. 返回的 Map 是不可变的,尝试修改会抛出 UnsupportedOperationException
  2. 如果传入的 entries 数组为 null,会抛出 NullPointerException
  3. 性能考虑:对于非常大的 Map,考虑使用 HashMap 然后包装为不可变

实际应用场景

// 创建配置 Map
Map<String, String> config = Map.ofEntries(entry("server.host", "localhost"),entry("server.port", "8080"),entry("db.url", "jdbc:mysql://localhost:3306/mydb"),entry("db.username", "admin"),entry("db.password", "secret")
);// 创建枚举值映射
Map<Integer, String> statusCodes = Map.ofEntries(entry(200, "OK"),entry(404, "Not Found"),entry(500, "Internal Server Error")
);

   Map.ofEntries() 提供了比 Map.of() 更灵活的方式来创建包含较多元素的不可变 Map,特别适合需要一次性初始化较多键值对的场景。

*/
//1.创建Map集合的对象
Map<String, String> m = new HashMap<>();//2.添加元素
//put方法的细节:PUT方法是有返回值的`
//添加/覆盖
//在添加数据的时候,如果键不存在,那么直接把键值对对象添加到map集合当中,方法返回null
//在添加数据的时候,如果键是存在的,那么会把原有的键值对对象覆盖,会把被覆盖的值进行返回。

遍历方法

//Map集合的第一种遍历方式//三个课堂练习:
//
//练习一:  利用键找值的方式遍历map集合,要求:装着键的单列集合使用增强for的形式进行遍历
//练习二:  利用键找值的方式遍历map集合,要求:装着键的单列集合使用迭代器的形式进行遍历
//练习三:  利用键找值的方式遍历map集合,要求:装着键的单列集合使用lambda表达式的形式进行遍历
// 练习一:增强for循环遍历键集合
Set<String> keySet1 = map.keySet();
for (String key : keySet1) {String value = map.get(key);System.out.println("键:" + key + ",值:" + value);
}// 练习二:迭代器遍历键集合
Set<String> keySet2 = map.keySet();
Iterator<String> iterator = keySet2.iterator();
while (iterator.hasNext()) {String key = iterator.next();String value = map.get(key);System.out.println("键:" + key + ",值:" + value);
}// 练习三:Lambda表达式遍历键集合
Set<String> keySet3 = map.keySet();
keySet3.forEach(key -> {String value = map.get(key);System.out.println("键:" + key + ",值:" + value);
});
//Map集合的第二种遍历方式//三个课堂练习:
//练习一:  通过键值对对象进行遍历map集合,要求:装着键值对对象的单列集合使用增强for的形式进行遍历
//练习二:  通过键值对对象进行遍历map集合,要求:装着键值对对象的单列集合使用迭代器的形式进行遍历
//练习三:  通过键值对对象进行遍历map集合,要求:装着键值对对象的单列集合使用lambda的形式进行遍历
// 练习一:增强for遍历Entry集合
Set<Map.Entry<String, Integer>> entrySet1 = map.entrySet();
for (Map.Entry<String, Integer> entry : entrySet1) {String key = entry.getKey();Integer value = entry.getValue();System.out.println(key + ":" + value);
}// 练习二:迭代器遍历Entry集合
Set<Map.Entry<String, Integer>> entrySet2 = map.entrySet();
Iterator<Map.Entry<String, Integer>> iterator = entrySet2.iterator();
while (iterator.hasNext()) {Map.Entry<String, Integer> entry = iterator.next();String key = entry.getKey();Integer value = entry.getValue();System.out.println(key + ":" + value);
}// 练习三:Lambda表达式遍历Entry集合
Set<Map.Entry<String, Integer>> entrySet3 = map.entrySet();
entrySet3.forEach(entry -> {String key = entry.getKey();Integer value = entry.getValue();System.out.println(key + ":" + value);
});

 

        //3.利用lambda表达式进行遍历//底层://forEach其实就是利用第二种方式进行遍历,依次得到每一个键和值//再调用accept方法map.forEach(new BiConsumer<String, String>() {@Overridepublic void accept(String key, String value) {System.out.println(key + "=" + value);}});System.out.println("-----------------------------------");map.forEach((String key, String value)->{System.out.println(key + "=" + value);});System.out.println("-----------------------------------");map.forEach((key, value)-> System.out.println(key + "=" + value));}
/*LinkedHashMap:由键决定:有序、不重复、无索引。有序:保证存储和取出的顺序一致原理:底层数据结构是依然哈希表,只是每个键值对元素又额外的多了一个双链表的机制记录存储的顺序。*/

 

HashMap在Java8后的改进(包含Java8)

①初始化时机:
①Java8之前,构造方法执行时初始化table数组。
②Java8之后,第一次调用put方法时初始化table数组。
②插入法:
①Java8之前,头插法
②Java8之后,尾插法
③数据结构:
①Java8之前:数组 + 单向链表
②Java8之后:数组 + 单向链表 + 红黑树。
③最开始使用单向链表解决哈希冲突。如果结点数量 >= 8,并且table的长度 >= 64。单向链表转换为红黑树。
④当删除红黑树上的结点时,结点数量 <= 6 时。红黑树转换为单向链表。

 

 

 

HashMap初始化容量永远都是2的次幂

①HashMap集合初始化容量16(第一次调用put方法时初始化)
②HashMap集合的容量永远都是2的次幂,假如给定初始化容量为31,它底层也会变成32的容量。
③将容量设置为2的次幂作用是:加快哈希计算,减少哈希冲突。
④为什么会加快哈希计算?
①首先,使用二进制运算是最快的。
②当一个数字是2的次幂时,例如数组的长度是2的次幂:
①hash & (length-1) 的结果和 hash % length的结果相同。
②注意:只有是2的次幂时,以上等式才会成立。因为了使用 & 运算符,让效率提升,因此建议容量一直是2的次幂。
⑤为什么会减少哈希冲突?
①底层运算是:hash & length - 1
②如果length是偶数:length-1后一定是奇数,奇数二进制位最后一位一定是1,1和其他二进制位进行与运算,结果可能是1,也可能是0,这样可以减少哈希冲突,让散列分布更加均匀。
③如果length是奇数:length-1后一定是偶数,偶数二进制位最后一位一定是0,0和任何数进行与运算,结果一定是0,这样就会导致发生大量的哈希冲突,白白浪费了一半的空间。

 

关于HashMap的初始化容量的设置

①当哈希表中的元素越来越多的时候,散列碰撞的几率也就越来越高(因为数组的长度是固定的),从而导致单链表过长,降低了哈希表的性能,此时我们就需要对哈希表进行扩容操作。
②那么HashMap什么时候进行扩容呢?当执行put()操作的时候,如果HashMap中存储元素的个数超过“数组长度* loadFactor”的结果(loadFactor指的是负载因子,loadFactor的默认值一般为0.75),那么就需要执行数组扩容操作。
③所谓的扩容操作,就是把数组的空间大小扩大一倍,然后遍历哈希表中元素,把这些元素重新均匀分散到扩容后的哈希表中。例如,默认情况下,数组大小为16,那么当HashMap中元素个数超过16*0.75=12的时候,就需要执行扩容操作,把数组的大小扩展为2*16=32,然后重新计算每个元素在数组中的位置,这是一个非常消耗性能的操作。
④为了避免扩容带来的性能损坏,建议使用哈希表之前,先预测哈希表需要存储元素的个数,提前为哈希表中的数组设置合适的存储空间大小,避免去执行扩容的操作,进一步提升哈希表的性能。例如:我们需要存储1000个元素,按照哈希表的容量设置为2的整数次幂的思想,我们设置哈希表的容量为1024更合适。但是0.75*1024 < 1024,需要执行消耗性能的扩容操作,因此我们设置哈希表的容量为2048更加合适,这样既考虑了&的问题,也避免了扩容的问题。
⑤思考:当我们创建一个HashMap对象,设置哈希表的容量为15,请问HashMap对象创建成功后,哈希表的实际容量为多少呢???
 
 
 

LinkedHashMap

①LinkedHashMap集合和HashMap集合的用法完全相同。
②不过LinkedHashMap可以保证插入顺序。
③LinkedHashMap集合因为可以保证插入顺序,因此效率比HashMap低一些。
④LinkedHashMap是如何保证插入顺序的?底层采用了双向链表来记录顺序。
⑤LinkedHashMap集合底层采用的数据结构是:哈希表 + 双向链表。
⑥LinkedHashMap集合的key是:有序不可重复。key部分也需要同时重写hashCode + equals。
⑦key的取值可以为null,key如果相同,value也是覆盖。
 
 
 
 
 

Hashtable

①Hashtable和HashMap一样,底层也是哈希表。
②Hashtable是线程安全的,方法上都有synchronized关键字。使用较少,因为保证线程安全有其他方式。
③Hashtable的初始化容量:11。默认加载因子:0.75
④Hashtable的扩容策略:2倍。
⑤Hashtable中有一些传统方法,这些方法不属于集合框架:
lEnumeration keys();  获取所有key的迭代器
lEnumeration elements();  获取所有value的迭代器
⑥Enumeration的相关方法
lboolean hasMoreElements();  是否含有元素
lE nextElement(); 获取元素
⑦Hashtable和HashMap集合的区别:
lHashMap集合线程不安全,效率高,key和value允许null。
lHashtable集合线程安全,效率低,key和value不允许null。

 

 

Properties

①Properties被称为属性类。通常和xxx.properties属性文件一起使用。
②Properties的父类是Hashtable。因此Properties也是线程安全的。
③Properties不支持泛型,key和value只能是String类型。
④Properties相关方法:
①Object setProperty(String key, String value);  和put方法一样。
②String getProperty(String key);  通过key获取value
③Set<String> propertyNames();  获取所有的key
 
 
 
 

 

TreeMap

①TreeMap底层就是红黑树。
②TreeMap和HashMap用法一样,只不过需要key排序的时候,就可以使用TreeMap。
③TreeMap的key不能是null。
④让TreeMap集合的key可排序,有两种方式:
①第一种方式:key实现了Comparable接口,并且提供了compareTo方法,在该方法中添加了比较规则。(比较规则不变的话建议这种。)
②第二种方式:创建TreeMap集合时,传一个比较器,比较器实现Comparator接口,在compare方法中添加比较规则。

 

http://www.xdnf.cn/news/16567.html

相关文章:

  • 适配鸿蒙低性能设备的终极优化方案:从启动到渲染全链路实战
  • IBus vs. Fcitx5:一场 Linux 输入法框架的正面交锋
  • Redis:缓存雪崩、穿透、击穿的技术解析和实战方案
  • HTTPS基本工作过程:基本加密过程
  • 河南萌新联赛2025第(三)场:河南理工大学【补题】
  • 2025最新版Node.js下载安装及环境配置教程【超详图文】
  • BGP高级特性之正则表达式
  • DFT不同维度中gate、cell、instance介绍
  • 智能体产品化的关键突破:企业智能化转型的“最后一公里”如何迈过?
  • Spring Cloud Gateway Server Web MVC报错“Unsupported transfer encoding: chunked”解决
  • Jupyter Notebook安装使用
  • WebRTC核心组件技术解析:架构、作用与协同机制
  • Java容器化实践:Docker+K8s部署Spring Boot应用全流程
  • LLM—— 基于 MCP 协议(Streamable HTTP 模式)的工具调用实践
  • 《设计模式之禅》笔记摘录 - 11.策略模式
  • 二叉树的学习
  • 【Java】批量生成Excel放入文件夹并打zip压缩包
  • 八种AI记忆术,重构智能体的“大脑”
  • RFID 系统行业前沿洞察:技术跃迁与生态重构
  • 线性代数常见的解题方法
  • aws(学习笔记第五十课) ECS集中练习(2)
  • 【MySQL 数据库】MySQL索引特性(二)页目录(B和B+树)(非)聚簇索引 索引操作
  • APM32芯得 EP.27 | 告别IDE,为APM32F411打造轻量级命令行开发工作流
  • 《Computational principles and challenges in single-cell data integration》
  • Vite 模块动态导入之Glob导入
  • 微算法科技MLGO突破性的监督量子分类器:纠缠辅助训练算法为量子机器学习开辟新天地
  • PCB学习笔记(一)
  • LeetCode 面试经典 150_数组/字符串_轮转数组(6_189_C++_中等)(额外数组;转置)
  • dify + mcp 实现图片 ocr 识别
  • 实例教学FPN原理与PANet,Pytorch逐行精讲实现