【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)方法时,就把keyvalue做了映射并放入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);}}
}

MapList不同的是,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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/187469.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

WPF实战项目十九(客户端):修改RestSharp的引用

修改HttpRestClient&#xff0c;更新RestSharp到110.2.0&#xff0c;因为106版本和110版本的代码不一样&#xff0c;所以需要修改下代码 using Newtonsoft.Json; using RestSharp; using System; using System.Threading.Tasks; using WPFProjectShared;namespace WPFProject.S…

算法通关村第十八关青铜挑战——透析回溯的模板

大家好&#xff0c;我是怒码少年小码。 回溯是最重要的算法思想之一&#xff0c;主要解决一些暴力枚举也搞不定的问题&#xff08;组合、子集、分割、排列、棋盘等等&#xff09;。性能并不高&#xff0c;但是哪些暴力枚举都无法ko的问题能解出来就可以了&#x1f923;。 这一…

apt镜像源——报错

目录 报错一:更新报错 报错二:更新404错误 报错三:vi 编辑器上下左右键无法使用,ABCD

BUUCTF [GXYCTF2019]BabySQli 1 详解!(MD5与SQL之间的碰撞)

题目环境burp抓包 随便输入值 repeater放包 在注释那里发现某种编码 MMZFM422K5HDASKDN5TVU3SKOZRFGQRRMMZFM6KJJBSG6WSYJJWESSCWPJNFQSTVLFLTC3CJIQYGOSTZKJ2VSVZRNRFHOPJ5 看着像是base编码格式 通过测试发现是套加密&#xff08;二次加密&#xff09; 首先使用base32对此编码…

项目11:豆瓣首页-页脚 完结撒花!

这次我们就来制作豆瓣首页的最后一部分页脚。 同样&#xff0c;页脚也在container中&#xff0c;页脚分为左区域和右区域&#xff0c;左区域里是多个p元素与a元素结合完成的&#xff0c;还要插入一些图片&#xff0c;右区域里里有几个横向菜单&#xff0c;以及一张图片。 左右…

近期知识点

aop (1) 要求利用AOP记录用户操作日志。内容包含以下信息&#xff1a;ip地址、用户名、请求的地址&#xff0c;请求的时间 &#xff08; 4 分&#xff09; &#xff08;2&#xff09;要求利用AOP记录用户操作日志&#xff0c;日志记录到文本文件。内容包含以下信息&#xff…

在Spring Boot中使用JavaMailSender发送邮件

用了这么久的Spring Boot&#xff0c;我们对Spring Boot的了解应该也逐步进入正轨了&#xff0c;这篇文章讲的案例也在我们的实际开发中算是比较实用的了&#xff0c;毕竟我们完成注册功能和对用户群发消息&#xff0c;都可以采用到邮箱发送功能&#xff0c;往下看&#xff0c;…

寿险公司通过开源治理保障数字创新,安全打通高质量服务新通道

某寿险公司致力于为消费者提供人性化的产品和服务&#xff0c;在中国保险市场中始终保持前列。该寿险公司以挖掘和满足客户需求为出发点&#xff0c;从产品开发、渠道销售、运营流程和售后服务等各环节&#xff0c;借助数字化工具&#xff0c;不断地努力探索并提升服务品质。 精…

C++ :运算符重载

运算符重载&#xff1a; 运算符重载概念&#xff1a;对已有的运算符重新进行定义&#xff0c;赋予其另一种功能&#xff0c;以适应不同的数据类型 运算符的重载实际是一种特殊的函数重载&#xff0c;必须定义一个函数&#xff0c;并告诉C编译器&#xff0c;当遇到该重载的运算符…

第二十章 控制 XML 元素和属性名称 - 控制列表类型属性的元素和属性名称

文章目录 第二十章 控制 XML 元素和属性名称 - 控制列表类型属性的元素和属性名称控制列表类型属性的元素和属性名称控制数组类型属性的元素和属性名称 第二十章 控制 XML 元素和属性名称 - 控制列表类型属性的元素和属性名称 控制列表类型属性的元素和属性名称 注意&#xf…

IDEA中的Postman!

Postman是大家最常用的API调试工具&#xff0c;那么有没有一种方法可以不用手动写入接口到Postman&#xff0c;即可进行接口调试操作&#xff1f;今天给大家推荐一款IDEA插件&#xff1a;Apipost Helper&#xff0c;写完代码就可以调试接口并一键生成接口文档&#xff01;而且还…

C语言声明(存储类别,作用域,链接属性)

声明 声明的语法 一般地&#xff0c;声明具有下列形式&#xff1a; 声明说明符 声明符;声明说明符&#xff08;declaration specifier&#xff09;描述声明的变量或函数的性质。 声明符&#xff08;declarator&#xff09;给出了它们的名字&#xff0c;并且可以提供关于其性质…

搭建Hadoop集群过程中常见错误的解决方案

格式化报错 权限问题 出现cannot creat directory或cannot creat file类型 如下报错信息&#xff1a; cannot create directory Permission denied如果使用的是 user 用户&#xff0c;多数情况下是因为文件权限问题&#xff0c;hadoop3.3.1、big_data&#xff08;存数据&am…

【Java】14. 字符串

14. 字符串 14.1 String类的构造方法 public class StringDemo01 {public static void main(String[] args) {//public String()&#xff1a;创建一个空白字符串对象&#xff0c;不含有任何内容String s1 new String();//public String(char[] chs)&#xff1a;根据字符数组的…

SAP 如何检查已安装的SAP UI5 版本

第一个方法是直接从FLP中查看 但是部分高版本的FLP中没有这个about&#xff0c; 那么在当前界面可以使用&#xff1a;CTRL ALT SHIFT S 查看当前版本 根据此版本&#xff0c;去进行你的UI5的开发吧

观察者模式

1.观察者模式是什么呢&#xff1f; 观察者模式&#xff08;有时又被称为发布-订阅Subscribe>模式、模型-视图View>模式、源-收听者Listener>模式或从属者模式&#xff09;是软件设计模式的一种。在此种模式中&#xff0c;一个目标物件管理所有相依于它的观察者物件&am…

2分图匹配算法

定义 节点u直接无边&#xff0c;v之间无边&#xff0c;边只存在uv之间。判断方法&#xff1a;BFS染色法&#xff0c;全部染色后&#xff0c;相邻边不同色 无权二部图中的最大匹配 最大匹配即每一个都匹配上min&#xff08;u&#xff0c; v&#xff09;。贪心算法可能导致&…

【Unity】Blender场景导入

素材 下载场景&#xff1a;https://www.aplaybox.com/details/model/keDSIks72Qh3 blender文件导出为.fbx文件&#xff0c;路径选择复制&#xff08;做的过程太乱了不知道有没有影响&#xff09;&#xff0c;物理类型选择网格&#xff0c;勾选应用变换 blender下的物体长度是u…

华为OD机试 - 计算三叉搜索树的高度(Java JS Python C)

题目描述 定义构造三叉搜索树规则如下: 每个节点都存有一个数,当插入一个新的数时,从根节点向下寻找,直到找到一个合适的空节点插入。查找的规则是: 如果数小于节点的数减去500,则将数插入节点的左子树如果数大于节点的数加上500,则将数插入节点的右子树否则,将数插入…

SS8813T 打印机驱动芯片

SS8813为打印机和其它电机一体化应用提供一种双通道集成电机驱动方案。SS8813有两路H桥驱动&#xff0c;每个H桥可提供最大峰值电流2.5A和均方根电流1.75A(在24V和Ta 25C适当散热条件下)&#xff0c;可驱动两个刷式直流电机&#xff0c;或者一个双极步进电机&#xff0c;或者螺…