【Java】集合 之 使用 Map
为什么使用Map
我们知道,List
是一种顺序列表,如果有一个存储学生Student
实例的List
,要在List
中根据name
查找某个指定的Student
的分数,应该怎么办?
最简单的方法是遍历List
并判断name
是否相等,然后返回指定元素:
List<Student> list = ...
Student target = null;
for (Student s : list) {if ("Xiao Ming".equals(s.name)) {target = s;break;}
}
System.out.println(target.score);
这种需求其实非常常见,即通过一个键去查询对应的值。使用List来实现存在效率非常低的问题,因为平均需要扫描一半的元素才能确定,而Map
这种键值(key-value)
映射表的数据结构,作用就是能高效通过key
快速查找value
(元素)。
用Map
来实现根据name
查询某个Student
的代码如下:
import java.util.HashMap;
import java.util.Map;
public class Main {public static void main(String[] args) {Student s = new Student("Xiao Ming", 99);Map<String, Student> map = new HashMap<>();map.put("Xiao Ming", s); // 将"Xiao Ming"和Student实例映射并关联Student target = map.get("Xiao Ming"); // 通过key查找并返回映射的Student实例System.out.println(target == s); // true,同一个实例System.out.println(target.score); // 99Student another = map.get("Bob"); // 通过另一个key查找System.out.println(another); // 未找到返回null}
}class Student {public String name;public int score;public Student(String name, int score) {this.name = name;this.score = score;}
}
通过上述代码可知:Map<K, V>
是一种键-值映射表,当我们调用put(K key, V value)
方法时,就把key
和value
做了映射并放入Map
。当我们调用V get(K key)
时,就可以通过key
获取到对应的value
。如果key
不存在,则返回null
。和List
类似,Map
也是一个接口,最常用的实现类是HashMap
。
如果只是想查询某个key
是否存在,可以调用boolean containsKey(K key)
方法。
如果我们在存储Map
映射关系的时候,对同一个key
调用两次put()
方法,分别放入不同的value
,会有什么问题呢?例如:
import java.util.HashMap;
import java.util.Map;
public class Main {public static void main(String[] args) {Map<String, Integer> map = new HashMap<>();map.put("apple", 123);map.put("pear", 456);System.out.println(map.get("apple")); // 123map.put("apple", 789); // 再次放入apple作为key,但value变为789System.out.println(map.get("apple")); // 789}
}
重复放入key-value
并不会有任何问题,但是一个key
只能关联一个value
。在上面的代码中,一开始我们把key
对象"apple"
映射到Integer
对象123
,然后再次调用put()
方法把"apple"
映射到789
,这时,原来关联的value
对象123
就被“冲掉”了。实际上,put()
方法的签名是V put(K key, V value)
,如果放入的key
已经存在,put()
方法会返回被删除的旧的value
,否则,返回null
。
始终牢记:Map
中不存在重复的key
,因为放入相同的key
,只会把原有的key-value
对应的value
给替换掉。
此外,在一个Map
中,虽然key
不能重复,但value
是可以重复的:
Map<String, Integer> map = new HashMap<>();
map.put("apple", 123);
map.put("pear", 123); // ok
遍历Map
对Map
来说,要遍历key
可以使用for each
循环遍历Map
实例的keySet()
方法返回的Set
集合,它包含不重复的key
的集合:
import java.util.HashMap;
import java.util.Map;
public class Main {public static void main(String[] args) {Map<String, Integer> map = new HashMap<>();map.put("apple", 123);map.put("pear", 456);map.put("banana", 789);for (String key : map.keySet()) {Integer value = map.get(key);System.out.println(key + " = " + value);}}
}Run
同时遍历key和value可以使用for each循环遍历Map对象的entrySet()集合,它包含每一个key-value映射:import java.util.HashMap;
import java.util.Map;
public class Main {public static void main(String[] args) {Map<String, Integer> map = new HashMap<>();map.put("apple", 123);map.put("pear", 456);map.put("banana", 789);for (Map.Entry<String, Integer> entry : map.entrySet()) {String key = entry.getKey();Integer value = entry.getValue();System.out.println(key + " = " + value);}}
}
Map
和List
不同的是,Map
存储的是key-value
的映射关系,并且,它不保证顺序。在遍历的时候,遍历的顺序既不一定是put()
时放入的key
的顺序,也不一定是key
的排序顺序。使用Map
时,任何依赖顺序的逻辑都是不可靠的。以HashMap
为例,假设我们放入"A"
,"B"
,"C"
这3个key
,遍历的时候,每个key
会保证被遍历一次且仅遍历一次,但顺序完全没有保证,甚至对于不同的JDK版本,相同的代码遍历的输出顺序都是不同的!
遍历Map
时,不可假设输出的key
是有序的!
练习
请编写一个根据name
查找score
的程序,并利用Map
充当缓存,以提高查找效率:
import java.util.*;
public class Main {public static void main(String[] args) {List<Student> list = List.of(new Student("Bob", 78),new Student("Alice", 85),new Student("Brush", 66),new Student("Newton", 99));var holder = new Students(list);System.out.println(holder.getScore("Bob") == 78 ? "测试成功!" : "测试失败!");System.out.println(holder.getScore("Alice") == 85 ? "测试成功!" : "测试失败!");System.out.println(holder.getScore("Tom") == -1 ? "测试成功!" : "测试失败!");}
}class Students {List<Student> list;Map<String, Integer> cache;Students(List<Student> list) {this.list = list;cache = new HashMap<>();}/*** 根据name查找score,找到返回score,未找到返回-1*/int getScore(String name) {// 先在Map中查找:Integer score = this.cache.get(name);if (score == null) {// TODO:}return score == null ? -1 : score.intValue();}Integer findInList(String name) {for (var ss : this.list) {if (ss.name.equals(name)) {return ss.score;}}return null;}
}class Student {String name;int score;Student(String name, int score) {this.name = name;this.score = score;}
}
小结
Map
是一种映射表,可以通过key
快速查找value
。
可以通过for each
遍历keySet()
,也可以通过for each
遍历entrySet()
,直接获取key-value
。
最常用的一种Map
实现是HashMap
。
相关文章:
【Java】集合 之 使用 Map
为什么使用Map 我们知道,List是一种顺序列表,如果有一个存储学生Student实例的List,要在List中根据name查找某个指定的Student的分数,应该怎么办? 最简单的方法是遍历List并判断name是否相等,然后返回指定…...

第二证券:股票几点到几点开盘?
作为股民或许投资者,我们都知道股票是每天都有开盘和收盘时间的。但是,关于股票的开盘时间,很多人并不是很清楚,特别是初学者。在本文中,我们将从多个视点分析股票开盘时间,并为大家供给一些有用的信息。 …...

goweb入门教程
本文是作者自己学习goweb时写的笔记,分享给大家,希望能有些帮助 前言: 关于web:本质 web中最重要的就是浏览器和服务器的request(请求)和response(响应); 一个请求对应一个响应。 一个请求对应一个响应&…...

量子计算:探索未来的计算技术
量子计算:探索未来的计算技术 引言 在过去的几十年里,我们见证了计算机技术从简单的计算和存储发展到复杂的数据处理和人工智能的飞速进步。然而,随着我们进一步探索科技的前沿,传统的计算方法开始显示出其局限性。在这种情况下,量子计算——一种基于量子力学原理的新型计…...
HarmonyOS应用开发者基础认证考试题目及答案
一、判断题 Ability是系统调度应用的最小单元,是能够完成一个独立功能的组件。一个应用可以包含一个或多个Ability。 正确(True) 所有使用Component修饰的自定义组件都支持onPageShow,onBackPress和onPageHide生命周期函数。 错误(False) 每调用一次ro…...

c# 文件读取和写入
文件写入 using System.Collections.Generic; namespace demo1;/// <summary> /// System.IO下的所有的Stream类是所有数据流的基类 /// 流是用于传输数据的对象,流就是用来传输数据的 /// 数据传输的两种方式:1、数据从外部源传输到程序中&#…...
【MySQL库的操作】
目录: 前言库的操作创建数据库字符集和校验规则校验规则对数据库的影响 选择和查看数据库修改数据库删除数据库备份注意事项查看连接情况 总结 前言 剑指offer:一年又二天 库的操作 创建、选择、查看、修改、删除与备份。 创建数据库 CREATE DATABASE…...
rocketmq 集群环境部署及与spring cloud 集成
1 下载zip 安装包 rocketmq-all-5.1.4-bin-release.zip 2 修改启动配置,防止默认内存配置过高 runserver.sh/runbroker.sh/tools.sh 3 启动namesrv nohup sh bin/mqnamesrv >>namesrv.log & 4 启动brokerproxy 单点模式: nohup sh bin…...

SpringBoot——配置及原理
优质博文:IT-BLOG-CN 一、Spring Boot全局配置文件 application.properties与application.yml配置文件的作用:可以覆盖SpringBoot配置的默认值。 ◀ YML(is not a Markup Language:不仅仅是一个标记语言)࿱…...

fiddler抓包安卓
一、打断点 1、安卓手机和电脑在同一局域网下,手机连接的网络开启手动代理,ip填写电脑ip,端口填写fiddler中配置的端口。 ip查看: 端口配置:tools-options-connections 2、安装证书,手机浏览器输入电脑ip…...

Maven 进阶学习指南---setting详解
前言 当我们在开发项目时,有时需要用到外部依赖组件,例如当我们需要 Json 序列化的时候需要用到 FastJson 组件,我们可以通过下载对应 jar 包加载到项目中。但当一个大的项目同时需要依赖各种各样的外部服务,就存在着配置繁琐、依…...
人工智能与我们的生活
人工智能对我们的生活影响有多大 1. 人工智能的领域 人工智能涉及的领域广泛,包括但不限于: a. 医疗保健领域 人工智能在医疗诊断、药物研发、患者管理等方面发挥了重要作用。医疗影像分析、基因组学研究等都受益于人工智能技术,为医学领…...
前端将blob转换为可下载的url及下载
一.转换 //将blob转换为url const changeBlobToUrl blobData > {return new Promise(resolve > {//创建Blob对象const blob new Blob([blobData])// 创建FileReader对象const reader new FileReader()reader.onload function (e) {resolve(e.target.result)}// 使用F…...

LVS-DR实验
实验前准备 DR服务器:192.168.188.11 192.168.188.15 NFS服务器:192.168.188.14 Web服务器1:192.168.188.12 Web服务器2:192.168.188.13 Vip:192.168.188.188 客户端:192.168.188.200 配置负载均衡调度…...

MYSQL索引使用注意事项
索引使用注意事项: 1.索引列运算 不要在索引列上进行运算操作,否则索引将失效; 2.字符串不加引号 字符串类型使用时,不加引号,否则索引将失效; 3.模糊查询 如果仅仅是尾部模糊匹配,索引将不会失…...

深入理解Java中的String、StringBuilder和StringBuffer(每天一个技术点,第一天)
大家好,我是你们的博主每天一个技术点。今天,我们将探讨Java中的一个重要主题:String、StringBuilder和StringBuffer。这些类在Java编程中无处不在,但它们之间的区别和用法可能并不是所有人都清楚。所以,让我们深入了解…...
PHP逻辑运算符学习资料
PHP逻辑运算符 在PHP中,逻辑运算符用于组合和比较不同的逻辑条件。下面是PHP中常用的逻辑运算符示例: 1. 与运算符(&& 或 and) $age 25; $isStudent true;if ($age > 18 && $isStudent) {echo "You …...
深入解析CPU工作原理与细节
计算机是现代社会中不可或缺的工具,而CPU(中央处理器)则是计算机的核心组件。CPU负责执行指令和控制计算机的各种操作,它的性能直接影响着计算机的速度和效率。 1. CPU的基本结构 CPU通常由以下几个主要组成部分构成:…...

计算机网络(超详解!) 第二节 物理层(上)
1.物理层的基本概念 物理层考虑的是怎样才能在连接各种计算机的传输媒体上传输数据比特流,而不是指具体的传输媒体。 物理层的作用是要尽可能地屏蔽掉不同传输媒体和通信手段的差异。 用于物理层的协议也常称为物理层规程(procedure)。 2.物理层的主要任务 主要…...
c++ 打怪升级
内联函数 调用时,直接会把代码拷贝到调用处; 函数指针 可以类比数组 //内联函数 调用时直接将代码拷贝过来 inline const string& longerStr(const string &s1,const string & s2){return s1.size()>s2.size() ? s1:s2; }int main(i…...

Docker 离线安装指南
参考文章 1、确认操作系统类型及内核版本 Docker依赖于Linux内核的一些特性,不同版本的Docker对内核版本有不同要求。例如,Docker 17.06及之后的版本通常需要Linux内核3.10及以上版本,Docker17.09及更高版本对应Linux内核4.9.x及更高版本。…...
DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径
目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...

Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)
文章目录 1.什么是Redis?2.为什么要使用redis作为mysql的缓存?3.什么是缓存雪崩、缓存穿透、缓存击穿?3.1缓存雪崩3.1.1 大量缓存同时过期3.1.2 Redis宕机 3.2 缓存击穿3.3 缓存穿透3.4 总结 4. 数据库和缓存如何保持一致性5. Redis实现分布式…...
可靠性+灵活性:电力载波技术在楼宇自控中的核心价值
可靠性灵活性:电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中,电力载波技术(PLC)凭借其独特的优势,正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据,无需额外布…...
linux 错误码总结
1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...
数据链路层的主要功能是什么
数据链路层(OSI模型第2层)的核心功能是在相邻网络节点(如交换机、主机)间提供可靠的数据帧传输服务,主要职责包括: 🔑 核心功能详解: 帧封装与解封装 封装: 将网络层下发…...

IT供电系统绝缘监测及故障定位解决方案
随着新能源的快速发展,光伏电站、储能系统及充电设备已广泛应用于现代能源网络。在光伏领域,IT供电系统凭借其持续供电性好、安全性高等优势成为光伏首选,但在长期运行中,例如老化、潮湿、隐裂、机械损伤等问题会影响光伏板绝缘层…...

pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)
目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关࿰…...
用鸿蒙HarmonyOS5实现中国象棋小游戏的过程
下面是一个基于鸿蒙OS (HarmonyOS) 的中国象棋小游戏的实现代码。这个实现使用Java语言和鸿蒙的Ability框架。 1. 项目结构 /src/main/java/com/example/chinesechess/├── MainAbilitySlice.java // 主界面逻辑├── ChessView.java // 游戏视图和逻辑├──…...

《Docker》架构
文章目录 架构模式单机架构应用数据分离架构应用服务器集群架构读写分离/主从分离架构冷热分离架构垂直分库架构微服务架构容器编排架构什么是容器,docker,镜像,k8s 架构模式 单机架构 单机架构其实就是应用服务器和单机服务器都部署在同一…...