Java
Map、Entry键值对
java.util.Map<k,v>
Map集合的特点:
- Map是一个双列集合,一个元素包含两个值(一个key,一个value)。
- Map集合中的元素,key和value的数据类型可以相同,也可以不同。
- Map集合中的元素,key是不可以重复的,而value是可以重复的。
- Map集合中的元素,key和value是一一对应的,一个key对应一个value。
java.util.HashMap<k,v>集合 implements Map<k,v>
HashMap集合的特点:
- HashMap集合底层是哈希表,查询速度快
- HashMap集合是一个无序的集合,存储元素和取出元素的顺序有可能不一致
java.util.LinkedHashMap<k,v>集合 extends HashMap<k,v>集合
LinkedHashMap的特点;
- LinkedHashMap集合底层是哈希表+链表。
- LinkedHashMap集合是一个有序的集合,存储元素和取出元素的顺序是一致的
常用方法:
- public V put(K key, V value)
定义:把指定的键与指定的值添加到Map集合中。
返回值 :v
存储键值对,key不重复,返回值v是null
存储键值对,key重复,会使用新的value替换map中重复的value,返回被替换的value。
package com.it.god.controller;
import java.util.HashMap;
import java.util.Map;
public class MapTest01 {
public static void main(String[] args) {
Map<String, String> map = new HashMap<>();
String v1 = map.put("张三", "李四");
System.out.println("v1:" + v1);//v1:null
String v2 = map.put("张三", "王五");
System.out.println("v2:" + v2);//v2:李四
System.out.println(map);
//要想往里添加,则参照下列方法
map.put("血手人屠", "铁剑山河");
map.put("心魔", "血菩萨");
System.out.println(map);
}
}
....................................................................................................................
v1:null
v2:李四
{张三=王五}
{张三=王五, 血手人屠=铁剑山河, 心魔=血菩萨}
2.public V remove(Object key)
定义:把指定的键所对应的键值元素 在Map集合中删除,返回被删除元素的值。
返回值:v
key存在,v返回被删除的值
key不存在,v返回null
private static void test02(){
Map<String, Integer> map = new HashMap<>();
map.put("苏檀儿", 1);
map.put("小婵", 2);
map.put("聂云竹", 3);
map.put("宁毅", 4);
System.out.println(map);
Integer v1 = map.remove("宁毅");
System.out.println("v1:" + v1);//返回被删除key对应的值
System.out.println(map);
Integer v2 = map.remove("苏文昱");
System.out.println("v2:" + v2);//返回null
System.out.println(map);
}
...................................................................................................................
{聂云竹=3, 苏檀儿=1, 小婵=2, 宁毅=4}
v1:4
{聂云竹=3, 苏檀儿=1, 小婵=2}
v2:null
{聂云竹=3, 苏檀儿=1, 小婵=2}
- public V get(Object key)
定义:根据指定的键,在Map集合中获取对应的值。
返回值:
key存在,返回对应的value值
key不存在,返回null
private static void test03() {
Map<String, Integer> map = new HashMap<>();
map.put("苏檀儿", 1);
map.put("小婵", 2);
map.put("聂云竹", 3);
map.put("宁毅", 4);
System.out.println(map);
Integer v1 = map.get("苏檀儿");
System.out.println("v1:"+v1);//获取key键对应的value值
Integer v2 = map.get("苏文方");
System.out.println("v2:"+v2);//key不存在,获取不到值,返回null
}
.............................................................................................................
{聂云竹=3, 苏檀儿=1, 小婵=2, 宁毅=4}
v1:1
v2:null
4.public boolean containsKey(Object key)
定义:判断集合中是否包含指定的键。
返回值:
包含返回true,不包含返回false。
private static void test04() {
Map<String, Integer> map = new HashMap<>();
map.put("苏檀儿", 1);
map.put("小婵", 2);
map.put("聂云竹", 3);
map.put("宁毅", 4);
System.out.println(map);
boolean v1 = map.containsKey("苏檀儿");
System.out.println("v1:"+v1);//在map中查找是否存在key键,存在返回true
boolean v2 = map.containsKey("苏文星");
System.out.println("v2:"+v2);//在map中查找是否存在key键,不存在返回false
}
.............................................................................................................
{聂云竹=3, 苏檀儿=1, 小婵=2, 宁毅=4}
v1:true
v2:false
方法 | 描述 |
clear() | 删除 hashMap 中的所有键/值对 |
clone() | 复制一份 hashMap |
isEmpty() | 判断 hashMap 是否为空 |
size() | 计算 hashMap 中键/值对的数量 |
putAll() | 将所有键/值对添加到 hashMap 中 |
putIfAbsent() | 如果 hashMap 中不存在指定的键,则将指定的键/值对插入到 hashMap 中。 |
containsValue() | 检查 hashMap 中是否存在指定的 value 对应的映射关系。 |
replace() | 替换 hashMap 中是指定的 key 对应的 value。 |
replaceAll() | 将 hashMap 中的所有映射关系替换成给定的函数所执行的结果。 |
getOrDefault() | 获取指定 key 对应对 value,如果找不到 key ,则返回设置的默认值 |
forEach() | 对 hashMap 中的每个映射执行指定的操作。 |
values() | 返回 hashMap 中存在的所有 value 值。 |
merge() | 添加键值对到 hashMap 中 |
compute() | 对 hashMap 中指定 key 的值进行重新计算 |
computeIfAbsent() | 对 hashMap 中指定 key 的值进行重新计算,如果不存在这个 key,则添加到 hasMap 中 |
computeIfPresent() | 对 hashMap 中指定 key 的值进行重新计算,前提是该 key 存在于 hashMap 中。 |
示例:
public static void main(String[] args) {
show01();
}
private static void show01() {
HashMap<String,String > map = new HashMap<>();
boolean result = map.isEmpty();//为空 true
System.out.println("集合是否为空" + result);
map.put("苏檀儿", "宁曦");
map.put("小婵", "宁忌");
map.put("聂云竹", "宁雯雯");
map.put("元锦儿", "宁珂");
System.out.println(map);
System.out.println("-----------");
//putIfAbsent() 方法会先判断指定的键(key)是否存在,不存在则将键/值对插入到 HashMap 中
//不存在该key,进行插入
map.putIfAbsent("刘西瓜", "宁凝");
System.out.println(map);
System.out.println("-----------");
result = map.isEmpty();//false
System.out.println("集合是否为空"+result);
System.out.println("-----------");
// containsValue() 方法,检测value中是否存在该值
if(map.containsValue("宁曦")) {
System.out.println("宁曦 存在于 map 中");
}
System.out.println("-----------");
if (!map.containsValue("宁轶")) {
map.put("呜呜呜", "宁轶");
}
System.out.println("Updated map HashMap: " + map);
System.out.println("-----------");
// 获得该 HashMap 中键/值对映射的数量
int size = map.size();
System.out.println("Size of HashMap: " + size);
System.out.println("-----------");
HashMap<String,String > v1 = (HashMap<String, String>) map.clone();
System.out.println(v1);
System.out.println("-----------");
HashMap<String, String> map02 = new HashMap<>();
map02.put("lalala", "aaa");
// 将所有的映射关系从 map 添加到 map02
map02.putAll(map);
System.out.println("map02->>" + map02);
System.out.println("-----------");
map.clear();
HashMap<String,String > maps = new HashMap<>();
maps.put("1", "Google");
maps.put("2", "BaiDu");
maps.put("3", "SouGou");
System.out.println("maps HashMap: " + maps);
//replaceAll() 使用以下方式将value值转换为大写
maps.replaceAll((key,value) -> value.toUpperCase());
System.out.println("Updated maps HashMap: " + maps);
//getOrDefault() 方法获取指定 key 对应对 value,如果找不到 key ,则返回设置的默认值。
String value1 = maps.getOrDefault("1", "not found");
System.out.println(value1);
System.out.println("-----------");
String value2 = maps.getOrDefault("4", "not found");
System.out.println(value2);
System.out.println("-----------");
show02();
}
private static void show02() {
// 创建一个 HashMap
HashMap<String, Integer> prices = new HashMap<>();
//往 HashMap 中插入值
prices.put("Shoes", 200);
prices.put("Bag", 300);
prices.put("Pant", 150);
System.out.println(" Price: " + prices);
// 返回所有value值组成的视图
Collection<Integer> vips = prices.values();
System.out.println(vips);
//merge() 方法会先判断指定的 key 是否存在,如果不存在,则添加键值对到 hashMap 中。
//匿名函数 lambda表达式 (oldValue, newValue) -> oldValue + newValue) 作为重新映射函数。
Integer vvipInteger = prices.merge("shirt", 30, (oldValue,newValue) -> oldValue + newValue);
//因为键 Shirt 并不在 prices 中,merge() 方法将映射 Shirt=100 插入到 prices,重新映射函数的执行结果被忽略。
System.out.println("Price of Shirt: " + vvipInteger);
System.out.println("-----------");
//compute() 方法对 hashMap 中指定 key 的值进行重新计算。
int newPrice = prices.compute("Shoes", (key,value) -> value - value * 10/100);
System.out.println("Discounted Price of Shoes: " + newPrice);
System.out.println("Updated HashMap: " + prices);
System.out.println("-----------");
System.out.println("update Price: ");
//通过 lambda 表达式使用 forEach()
prices.forEach((key,value) -> {
// value 价格减少百分之 10
value = value - value * 10/100;
System.out.println(key + "="+ value + " ");
});
System.out.println("-----------");
show03();
}
private static void show03() {
// 创建一个 HashMap
HashMap<String, Integer> prices = new HashMap<>();
// 往HashMap中添加映射项
prices.put("Shoes", 200);
prices.put("Bag", 300);
prices.put("Pant", 150);
System.out.println("HashMap: " + prices);
//computeIfAbsent() 方法对 hashMap 中指定 key 的值进行重新计算,
//如果不存在这个 key,则添加到 hasMap 中。
int shirtPrice = prices.computeIfAbsent("Shirt", key -> 280);
System.out.println("Price of Shirt: " + shirtPrice);
// 输出更新后的HashMap
System.out.println("Updated HashMap: " + prices);
System.out.println("-----------");
//当shirt映射关系存在时,将不改变其值。
shirtPrice = prices.computeIfAbsent("Shirt", key -> 380);
System.out.println("Price of Shirt: " + shirtPrice);
// 输出更新后的HashMap
System.out.println("Updated HashMap: " + prices);
System.out.println("-----------");
show04();
}
private static void show04() {
// 创建一个 HashMap
HashMap<String, Integer> prices = new HashMap<>();
// 往HashMap中添加映射关系
prices.put("Shoes", 200);
prices.put("Bag", 300);
prices.put("Pant", 150);
System.out.println("HashMap: " + prices);
//computeIfPresent() 方法对 hashMap 中指定 key 的值进行重新计算,
//前提是该 key 存在于 hashMap 中。
// 重新计算鞋加上10%的增值税后的价值
int shoesPrice = prices.computeIfPresent("Shoes", (key,value) -> value + value * 10/100);
System.out.println("Price of Shoes after : " + shoesPrice);
// 输出更新后的HashMap
System.out.println("Updated HashMap: " + prices);
}
.................................................................................................................
集合是否为空true
{聂云竹=宁雯雯, 苏檀儿=宁曦, 小婵=宁忌, 元锦儿=宁珂}
-----------
{刘西瓜=宁凝, 聂云竹=宁雯雯, 苏檀儿=宁曦, 小婵=宁忌, 元锦儿=宁珂}
-----------
集合是否为空false
-----------
宁曦 存在于 map 中
-----------
Updated map HashMap: {刘西瓜=宁凝, 聂云竹=宁雯雯, 苏檀儿=宁曦, 呜呜呜=宁轶, 小婵=宁忌, 元锦儿=宁珂}
-----------
Size of HashMap: 6
-----------
{刘西瓜=宁凝, 聂云竹=宁雯雯, 苏檀儿=宁曦, 呜呜呜=宁轶, 小婵=宁忌, 元锦儿=宁珂}
-----------
map02->>{刘西瓜=宁凝, 聂云竹=宁雯雯, 苏檀儿=宁曦, lalala=aaa, 呜呜呜=宁轶, 小婵=宁忌, 元锦儿=宁珂}
-----------
maps HashMap: {1=Google, 2=BaiDu, 3=SouGou}
Updated maps HashMap: {1=GOOGLE, 2=BAIDU, 3=SOUGOU}
GOOGLE
-----------
not found
-----------
Price: {Pant=150, Bag=300, Shoes=200}
[150, 300, 200]
Price of Shirt: 30
-----------
Discounted Price of Shoes: 180
Updated HashMap: {Pant=150, shirt=30, Bag=300, Shoes=180}
-----------
update Price:
Pant=135
shirt=27
Bag=270
Shoes=162
-----------
HashMap: {Pant=150, Bag=300, Shoes=200}
Price of Shirt: 280
Updated HashMap: {Pant=150, Shirt=280, Bag=300, Shoes=200}
-----------
Price of Shirt: 280
Updated HashMap: {Pant=150, Shirt=280, Bag=300, Shoes=200}
-----------
HashMap: {Pant=150, Bag=300, Shoes=200}
Price of Shoes after : 220
Updated HashMap: {Pant=150, Bag=300, Shoes=220}
Map集合遍历方式:
一、通过键找值的方式
Map集合中的方法:
public Set keySet()
定义:返回此映射中包含的键的set视图。
实现步骤:
- 使用map集合中的方法 keySet(),把map集合所有的key取出来,存储到一个Set集合中
- 遍历set集合,获取map集合中的每一个key
- 通过map集合中的方法get(key),通过key找到value
private static void test05() {
Map<String, Integer> map = new HashMap<>();
map.put("苏檀儿", 1);
map.put("小婵", 2);
map.put("聂云竹", 3);
map.put("宁毅", 4);
//使用map集合中的方法 keySet(),把map集合所有的key取出来,存储到一个Set集合中
Set<String> set = map.keySet();
//遍历set集合,获取map集合中的每一个key
//1.使用迭代器遍历set集合
Iterator<String> it = set.iterator();
while(it.hasNext()){
String key = it.next();
//通过map集合中的方法get(key),通过key找到value
Integer value = map.get(key);
System.out.println(key+"="+value);
}
System.out.println("------------------------------------------------------");
//2.使用增强for遍历set集合
for(String key : map.keySet()){
Integer value = map.get(key);
System.out.println(key+"="+value);
}
}
.....................................................................................................................
聂云竹=3
苏檀儿=1
小婵=2
宁毅=4
------------------------------------------------------
聂云竹=3
苏檀儿=1
小婵=2
宁毅=4
二、使用entry对象遍历
Map集合中的方法:public Set<Map.Entry<K,V>> entrySet()
定义:返回此映射中包含的映射关系的set视图。
实现步骤:
- 使用map集合中的方法entrySet(),把map集合集合中多个Entry对象取出来,存储到一个Set集合中。
- 遍历Set集合,获取每一个Entry对象
- 使用Entry对象中的getKey()和getValue()方法,获取键与值
private static void test06() {
Map<String, Integer> map = new HashMap<>();
map.put("苏檀儿", 1);
map.put("小婵", 2);
map.put("聂云竹", 3);
map.put("宁毅", 4);
// 1. 使用map集合中的方法entrySet(),把map集合集合中多个Entry对象取出来,存储到一个Set集合中。
Set<Map.Entry<String, Integer>> set = map.entrySet();
// 2. 遍历Set集合,获取每一个Entry对象
// 使用迭代器遍历set集合
Iterator<Map.Entry<String, Integer>> it = set.iterator();
while (it.hasNext()) {
Map.Entry<String, Integer> entry = it.next();
// 3. 使用Entry对象中的getKey()和getValue()方法,获取键与值
String key = entry.getKey();
Integer value = entry.getValue();
System.out.println(key + "=" + value);
}
System.out.println("------------------------------------------------------");
//使用增加for循环遍历set集合
for (Map.Entry<String, Integer> entry : map.entrySet() ) {
// 3. 使用Entry对象中的getKey()和getValue()方法,获取键与值
String key = entry.getKey();
Integer value = entry.getValue();
System.out.println(key + "=" + value);
}
}
.................................................................................................................
聂云竹=3
苏檀儿=1
小婵=2
宁毅=4
------------------------------------------------------
聂云竹=3
苏檀儿=1
小婵=2
宁毅=4
HashMap存储自定义类型键值
Map集合保证key是唯一的;
作为key的元素,必须重写hashCode和equals方法,以保证key唯一
①key:string类型
string类型重写hashCode和equals方法,可以保证key唯一
value:Persion类型
value可以重复(同名同年龄的视为同一个人)
public class Persion {
private String name;
private int age;
public Persion() {
}
public Persion(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Persion [name=" + name + ", age=" + age + "]";
}
}
private static void show01() {
// 创建HashMap集合
HashMap<String, Persion> map = new HashMap<>();
//往集合中添加元素
map.put("宁毅", new Persion("立恒",21 ));
map.put("苏檀儿", new Persion("檀儿",15 ));
map.put("小婵", new Persion("婵儿",14 ));
map.put("宁曦", new Persion("曦儿",6 ));
map.put("宁忌", new Persion("龙傲天",2 ));
//使用keySet加增强for循环遍历map集合
Set<String> set = map.keySet();
for(String key : set){
Persion value = map.get(key);
System.out.println(key+"-->"+value);
}
}
.................................................................................................................
宁忌-->Persion [name=龙傲天, age=2]
苏檀儿-->Persion [name=檀儿, age=15]
小婵-->Persion [name=婵儿, age=14]
宁曦-->Persion [name=曦儿, age=6]
宁毅-->Persion [name=立恒, age=21]
②key:Persion类型
Persion类型重写hashCode和equals方法,可以保证key唯一
value:string类型
value可以重复
public class Persion {
private String name;
private int age;
public Persion() {
}
public Persion(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Persion [name=" + name + ", age=" + age + "]";
}
}
private static void show02() {
// 创建HashMap集合
HashMap<Persion,String > map = new HashMap<>();
//往集合中添加元素
map.put(new Persion("立恒",21 ),"宁毅" );
map.put(new Persion("檀儿",15 ),"苏檀儿" );
map.put(new Persion("婵儿",14 ),"小婵" );
map.put(new Persion("曦儿",6 ),"宁曦" );
map.put(new Persion("龙傲天",2 ),"宁忌" );
map.put(new Persion("龙傲天",2 ),"无忌" );
//使用entrySet加增强for循环遍历map集合
Set<Map.Entry<Persion, String>> set = map.entrySet();
for (Map.Entry<Persion, String> entry :set ) {
Persion key = entry.getKey();
String value = entry.getValue();
System.out.println(key+"-->"+value);
}
}
.................................................................................................................
Persion [name=龙傲天, age=2]-->无忌
Persion [name=婵儿, age=14]-->小婵
Persion [name=龙傲天, age=2]-->宁忌
Persion [name=檀儿, age=15]-->苏檀儿
Persion [name=立恒, age=21]-->宁毅
Persion [name=曦儿, age=6]-->宁曦
key为Persion类型时,并不能保证是唯一的,这是因为Persion类中并没有重写hashcode和equals,将persion类修改如下:
public class Persion {
private String name;
private int age;
public Persion() {
}
public Persion(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Persion [name=" + name + ", age=" + age + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Persion other = (Persion) obj;
if (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
private static void show02() {
// 创建HashMap集合
HashMap<Persion,String > map = new HashMap<>();
//往集合中添加元素
map.put(new Persion("立恒",21 ),"宁毅" );
map.put(new Persion("檀儿",15 ),"苏檀儿" );
map.put(new Persion("婵儿",14 ),"小婵" );
map.put(new Persion("曦儿",6 ),"宁曦" );
map.put(new Persion("龙傲天",2 ),"宁忌" );
map.put(new Persion("龙傲天",2 ),"无忌" );
//使用entrySet加增强for循环遍历map集合
Set<Map.Entry<Persion, String>> set = map.entrySet();
for (Map.Entry<Persion, String> entry :set ) {
Persion key = entry.getKey();
String value = entry.getValue();
System.out.println(key+"-->"+value);
}
}
.................................................................................................................
Persion [name=婵儿, age=14]-->小婵
Persion [name=曦儿, age=6]-->宁曦
Persion [name=立恒, age=21]-->宁毅
Persion [name=檀儿, age=15]-->苏檀儿
Persion [name=龙傲天, age=2]-->无忌
重新测试,保证key是唯一的
LinkedHashMap集合
java.util.LinkedHashMap<K,V> entends HashMap<K,V>
Map接口的哈希表和链接列表实现,具有可预知的迭代顺序。
底层原理:
哈希表+链表(记录元素的顺序)是有序的
public static void main(String[] args) {
HashMap<String,String > map = new HashMap<>();
map.put("苏檀儿", "宁曦");
map.put("小婵", "宁忌");
map.put("聂云竹", "宁雯雯");
map.put("元锦儿", "宁珂");
System.out.println(map);// HashMap key不允许重复,且是无序的集合
System.out.println("-----------------------------------------------");
LinkedHashMap<String,String > linked = new LinkedHashMap<>();
linked.put("苏檀儿", "宁曦");
linked.put("小婵", "宁忌");
linked.put("聂云竹", "宁雯雯");
linked.put("元锦儿", "宁珂");
System.out.println(linked);//LinkedHashMap key不允许重复,且是有序的集合
}
.................................................................................................................
{聂云竹=宁雯雯, 苏檀儿=宁曦, 小婵=宁忌, 元锦儿=宁珂}
-----------------------------------------------
{苏檀儿=宁曦, 小婵=宁忌, 聂云竹=宁雯雯, 元锦儿=宁珂}
HashTable集合
java.util.Hashtable<K,V> implements Map<K,V>
HashTable:底层也是一个哈希表,是一个线程安全的集合,是单线程集合,速度慢
HashMap:底层是一个哈希表,是一个线程不安全的集合,是多线程的集合,速度快
HashMap集合:可以存储null值,null键
HashTable集合:不能存储null值,null键
public static void main(String[] args) {
HashMap<String,String > map = new HashMap<>();
map.put(null, "苏檀儿");
map.put("宁毅", null);
map.put(null, null);
System.out.println(map);//HashMap允许存在null值,null键
Hashtable<String, String> table = new Hashtable<>();
table.put(null, "杏儿");//发生报错,空指针异常,不允许存在null值,null键
table.put("杏儿",null );//发生报错,空指针异常,不允许存在null值,null键
table.put(null, null);//发生报错,空指针异常,不允许存在null值,null键
}
.................................................................................................................
{null=null, 宁毅=null}
Exception in thread "main" java.lang.NullPointerException
at java.util.Hashtable.put(Hashtable.java:465)
at com.it.god.hashtable.HashTableTest.main(HashTableTest.java:17)