Map详解

2022-07-27,

1、map集合概述

public interface Map
首先看一下map接口,我们可以看到map的存值结构以键值对结构,简单来说,map集合就是一个将键(key)映射到值(value)的对象且一个映射不可以包含重复的键,每个键只能映射到一个值。

2、map的存储结构

 

如上图所示,map中存储数据的方式是一个key对应一个value值

所有key不能重复,没有顺序,相当于一个Set集合。

key值可为null,但由于key的值不可重复,故key为null的情况也只可以有一次

value的值可以重复也可以多个为null

一对键值对底层是放在一个entry数组中

查询的时候是根据键(key)键的值的hashcode值找寻value所对应的位置,如果对同一个键多次赋value的值,那么后赋的值会覆盖前面赋的值.

3、总结一下map的一些特点

Map集合是一个双列集合,一个元素包含两个值(一个key,一个value)。

Map集合中的元素,key和value的数据类型可以相同,也可以不同。

Map集合中的元素,key是不允许重复的, value是可以重复的。

Map集合中的元素,key和 value是一一对应的。

4、map的实现类

下面挑几个比较常用的实现类来讲解

4.1 HashMap

这是我们日常使用比较多的一个实现类. 它的底层实现方式是数组+链表,key和value的值都可以为null. 初始的内存大小为16,一般存储元素到达大小的一半的时候进行扩容. 线程不安全,但优点在于效率比较高. HashMap不支持同步,即同一时刻多个线程同时进行写操作是可能会导致数据的不一致,若需要支持同步的话,可以使用collections的synchronizedmap方法.

4.2 Hashtable

它的底层实现是数组+链表,key和value不可以存储null. 因为给大多数的操作都加了锁的缘故,所以Hashtable支持同步操作,但也正是这一点,导致了Hashtable的写入速度较慢,在对于数据的安全级别要求较高的时候使用.

4.3 ConcurrentHashMap

它的底层实现是分段数组+链表. Hashtable的synchronized是针对整张Hash表的,即每次锁住整张表让线程独占

ConcurrentHashMap允许多个修改操作并发进行,其关键在于使用了锁分离技术 通过把整个Map分为N个Segment,可以提供相同的线程安全,但是效率提升N倍,默认提升16倍.

4.4 linkedHashMap

LinkedHashMap可以认为是HashMap和LinkedList合体,即它既使用HashMap操作数据结构,又使用LinkedList维护插入元素的先后顺序. 内部维持了一个双向链表. LinkedHashMap是HashMap的子类. 它的元素按照插入顺序排列. 遍历速度较慢.

4.5 TreeMap

基于红黑树(Red-Black tree)的 NavigableMap 实现.该映射根据其键的自然顺序进行排序,或者根据创建映射时提供的 Comparator 进行排序.具体取决于使用的构造方法。优点是键值可排序,唯一,值有序可重复,底层数据结构是平衡二叉树.

5、map常用方法

void clear():删除该Map对象中所有键值对;

boolean containsKey(Object key):查询Map中是否包含指定的key值;

boolean containsValue(Object value):查询Map中是否包含一个或多个value;

Set entrySet():返回map中包含的键值对所组成的Set集合,每个集合都是Map.Entry对象。

Object get():返回指定key对应的value,如果不包含key则返回null;

boolean isEmpty():查询该Map是否为空;

Set keySet():返回Map中所有key组成的集合;

Collection values():返回该Map里所有value组成的Collection。

Object put(Object key,Object value):添加一个键值对,如果集合中的key重复,则覆盖原来的键值对;

void putAll(Map m):将Map中的键值对复制到本Map中;

Object remove(Object key):删除指定的key对应的键值对,并返回被删除键值对的value,如果不存在,则返回null;

boolean remove(Object key,Object value):删除指定键值对,删除成功返回true;

int size():返回该Map里的键值对个数;
内部类Entry

Map中包括一个内部类Entry,该类封装一个键值对,常用方法:

Object getKey():返回该Entry里包含的key值;
Object getvalue():返回该Entry里包含的value值;
Object setValue(V value):设置该Entry里包含的value值,并设置新的value值。
        HashMap<String, Integer> hm = new HashMap<>();

        //放入元素
        hm.put("Harry",23);
        hm.put("Jenny",24);
        hm.put("XiaoLi",20);

        System.out.println(hm);//{XiaoLi=20, Harry=23, Jenny=24}
        System.out.println(hm.keySet());//[XiaoLi, Harry, Jenny]
        System.out.println(hm.values());//[20, 23, 24]

        Set<Map.Entry<String, Integer>> entries = hm.entrySet();

        for (Map.Entry<String, Integer> entry : entries) {
            System.out.println(entry.getKey());
            System.out.println(entry.getValue());
        }
}

6、java8为Map新增的方法

default V getOrDefault(Object key, V defaultValue)

default void forEach(BiConsumer<? super K, ? super V> action)

default V putIfAbsent(K key, V value)putIfAbsent

Object compute(Object key,BiFurcation remappingFunction)

computeIfAbsent

computeIfPresent

merge

remove(key,value)

replace

replaceAll

getOrDefault

如果Map中不存在该key,可以提供一个默认值,方法会返回改默认值。如果存在该key,返回键对应的值。

java8之前的写法:

Map<String, String> map = new HashMap<>();
String value = "D";
if(map.containsKey("d")) {
	value = map.get("d");
}

java8:

String value = map.getOrDefault("d", "D");

forEach

default void forEach(BiConsumer<? super K, ? super V> action)

forEach遍历map,对map中的每个映射执行action指定的操作。

Map<String, String> map = new HashMap<>();
map.put("a", "A");
map.put("b", "B");

// 遍历
map.forEach((k, v)-> {
	System.out.println(k + "=" + v);
	map.put(k, k + v);
});
// 输出
// a=A
// b=B

map.forEach((k, v)-> {
	System.out.println(k + "=" + v);
});
// 输出
// a=aA
// b=bB

putIfAbsent

default V putIfAbsent(K key, V value)

V putIfAbsent(K key, V value)只有在不存在key值的映射或者映射值为null,才将value值赋值给key。否则不做修改。该方法将条件判断和赋值合二为一。

Map<String, String> map = new HashMap<>();
map.put("a", "A");
map.put("b", "B");
        
String e = map.putIfAbsent("e", "E");
String b = map.putIfAbsent("b", "E");
System.out.println("返回e="+e); //返回e=null
System.out.println("键e="+map.get("e"));//键e=E
System.out.println("返回b="+b);//返回b=B
System.out.println("键b="+map.get("b"));//键b=B

remove(key,value)

default boolean remove(Object key, Object value)

只有在当前Map中key映射的值等于value时才删除该映射,否则什么也不做。

Map<String, String> map = new HashMap<>();
map.put("a", "A");
map.put("b", "B");

map.remove("a", "B");
map.remove("b", "B");
System.out.println(map.get("a")); // A
System.out.println(map.get("b")); // null

replace(K key, V value)

只有在当前Map中包含key,才用value去替换原来的值,否则什么也不做。

Map<String, String> map = new HashMap<>();
map.put("a", "A");
map.put("b", "B");

map.replace("c", "1");
map.replace("b", "1");
System.out.println(map.get("c")); // null
System.out.println(map.get("b")); // 1

replace(K key, V oldValue, V newValue)

default boolean replace(K key, V oldValue, V newValue)

只有在当前Map中key的映射存在且映射的值等于oldValue时才用newValue去替换原来的值,否则什么也不做。

Map<String, String> map = new HashMap<>();
map.put("a", "A");
map.put("b", "B");

map.replace("a", "1", "2");
map.replace("b", "B", "2");
System.out.println(map.get("a")); // A
System.out.println(map.get("b")); // 2

replaceAll

default void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) { Objects.requireNonNull(function);

该方法签名为replaceAll(BiFunction<? super K,? super V,? extends V> function),作用是对Map中的每个映射执行function指定的操作,并用function的执行结果替换原来的value

Map<String, String> map = new HashMap<>();
map.put("a", "A");
map.put("b", "B");

map.replaceAll((k, v) -> v.toLowerCase());
map.forEach((k, v)-> {
	System.out.println(k + "=" + v);
});

// a=a
// b=b

merge

default V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction)

value和remappingFunction不能为null
如果Map中key对应的映射不存在或者为null,则将value关联到key上;否则执行remappingFunction,如果执行结果为null则删除key的映射,否则用该结果跟key关联。

Map<String, String> map = new HashMap<>();
map.put("e", "E");
map.merge("f", "F", String::concat);
map.merge("e", "F", String::concat);
System.out.println("map.get(\"f\")="+map.get("f")); // map.get("f")=F
System.out.println("map.get(\"e\")="+map.get("e")); // map.get("e")=EF
	

Object compute(Object key,BiFurcation remappingFunction)

default V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction)

使用remappingFunction根据原键值对计算一个新的value,只要新value不为null,就覆盖原value;如果新value为null则删除该键值对,如果同时为null则不改变任何键值对,直接返回null。

 Map<String, String> map = new HashMap<>();
        map.put("b", "B");
        map.put("c", "C");
        map.put("d", "D");
        String val = map.compute("b", (k, v) -> null);
        System.out.println(val);
        System.out.println(map);//{c=C, d=D}
        String val2 = map.compute("e", (k, v) -> v + "+v");
        System.out.println(val2);//null+v
        System.out.println(map);//{c=C, d=D, e=null+v}

computeIfAbsent

default V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction)

当Map中不存在key值的映射value或映射值value为null时,调用mappingFunction,并在mappingFunction执行结果非null时,将结果赋值给key。

比如(输入每个字母的位置):

List<String> list = Lists.newArrayList("a", "b", "b", "c", "c", "c", "d", "d", "d", "f", "f", "g");
Map<String, List<Integer>> positionsMap = new HashMap<>();
for (int i = 0; i < list.size(); i++) {
    positionsMap.computeIfAbsent(list.get(i), k -> Lists.newArrayListWithCapacity(1)).add(i);
}

System.out.println(positionsMap);
// {a=[0], b=[1, 2], c=[3, 4, 5], d=[6, 7, 8], f=[9, 10], g=[11]}

        HashMap<String, Integer> hm = new HashMap<>();
        //放入元素
        hm.put("Harry",23);
        hm.put("Jenny",24);
        hm.put("XiaoLi",20);
        hm.put("LiMing",null);
        //指定key为null则计算结果作为value
        hm.computeIfAbsent("LiMing",(key)->10);
        System.out.println(hm);//{XiaoLi=20, Harry=23, Jenny=24, LiMing=10}
        //如果指定key本来不存在,则添加对应键值对
        hm.computeIfAbsent("XiaoHong",(key)->34);
        System.out.println(hm);//{XiaoLi=20, Harry=23, XiaoHong=34, Jenny=24, LiMing=10}

 

借鉴:https://blog.csdn.net/mashaokang1314/article/details/83784159?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-2.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-2.control

 

 

 

本文地址:https://blog.csdn.net/mingyuli/article/details/110292564

《Map详解.doc》

下载本文的Word格式文档,以方便收藏与打印。