java集合学习笔记:map(代码片段)

笑虾 笑虾     2022-12-11     190

关键词:

Java 集合学习笔记:Map

UML

简介

将键映射到值的对象。一个映射不能包含重复的键;每个键最多只能映射到一个值。
.
此接口取代 Dictionary 类,后者完全是一个抽象类,而不是一个接口。
.
Map 接口提供三种 collection 视图,允许以键集、值集或键-值映射关系集的形式查看某个映射的内容。映射顺序 定义为迭代器在映射的 collection 视图上返回其元素的顺序。某些映射实现可明确保证其顺序,如 TreeMap 类;另一些映射实现则不保证顺序,如 HashMap 类。
.
注:将可变对象用作映射键时必须格外小心。当对象是映射中某个键时,如果以影响 equals 比较的方式更改了对象的值,则映射的行为将是不确定的。此项禁止的一种特殊情况是不允许某个映射将自身作为一个键包含。虽然允许某个映射将自身作为值包含,但请格外小心:在这样的映射上 equalshashCode 方法的定义将不再是明确的。
.
所有通用的映射实现类应该提供两个“标准的”构造方法:一个 void(无参数)构造方法,用于创建空映射;一个是带有单个 Map 类型参数的构造方法,用于创建一个与其参数具有相同键-值映射关系的新映射。实际上,后一个构造方法允许用户复制任意映射,生成所需类的一个等价映射。尽管无法强制执行此建议(因为接口不能包含构造方法),但是 JDK 中所有通用的映射实现都遵从它。
.
此接口中包含的“破坏”方法可修改其操作的映射,如果此映射不支持该操作,这些方法将抛出 UnsupportedOperationException。如果是这样,那么在调用对映射无效时,这些方法可以(但不要求)抛出 UnsupportedOperationException。例如,如果某个不可修改的映射(其映射关系是“重叠”的)为空,则对该映射调用 putAll(Map) 方法时,可以(但不要求)抛出异常。
.
某些映射实现对可能包含的键和值有所限制。例如,某些实现禁止 null 键和值,另一些则对其键的类型有限制。尝试插入不合格的键或值将抛出一个未经检查的异常,通常是 NullPointerExceptionClassCastException。试图查询是否存在不合格的键或值可能抛出异常,或者返回 false;某些实现将表现出前一种行为,而另一些则表现后一种。一般来说,试图对不合格的键或值执行操作且该操作的完成不会导致不合格的元素被插入映射中时,将可能抛出一个异常,也可能操作成功,这取决于实现本身。这样的异常在此接口的规范中标记为“可选”。
.
此接口是 Java Collections Framework 的成员。
.
Collections Framework 接口中的很多方法是根据 equals 方法定义的。例如,containsKey(Object key) 方法的规范中写道:“当且仅当此映射包含针对满足 (key==null ? k==null : key.equals(k)) 的键 k 的映射关系时,返回 true”。不 应将此规范解释为:调用具有非空参数 keyMap.containsKey 将导致对任意的键 k 调用 key.equals(k)。实现可随意进行优化,以避免调用 equals,例如,可首先比较两个键的哈希码(Object.hashCode() 规范保证哈希码不相等的两个对象不会相等)。一般来说,只要实现者认为合适,各种 Collections Framework 接口的实现可随意利用底层 Object 方法的指定行为。

源码阅读

嵌套类

interface Entry<K,V>

https://docs.oracle.com/javase/8/docs/api/java/util/Map.Entry.html
Map 中存放的是 EntryEntry 中再存放 Key、Value

HashMap 中有实现 static class Node<K,V> implements Map.Entry<K,V> 详情看 HashMap 学习笔记。

静态方法

访问修饰符&返回类型方法描述
static <K extends Comparable<? super K>,V> Comparator<Map.Entry<K,V>>comparingByKey()返回一个比较器。按 key 升序排列 Map.Entry
static <K,V> Comparator<Map.Entry<K,V>>comparingByKey(Comparator<? super K> cmp)返回一个比较器,使用给定的 key 比较 Map.Entry
static <K,V extends Comparable<? super V>> Comparator<Map.Entry<K,V>>comparingByValue()返回一个比较器。按 value 升序排列 Map.Entry
static <K,V> Comparator<Map.Entry<K,V>>comparingByValue(Comparator<? super V> cmp)返回一个比较器,使用给定的 value 比较 Map.Entry
booleanequals(Object o)比较指定对象与此项的相等性。
KgetKey()返回与此项对应的键。
VgetValue()返回与此项对应的值。
inthashCode()返回此映射项的哈希码值。
VsetValue(V value)用指定的值替换与此项对应的值(可选操作)。

comparingByKey()

默认使用 key自然升序 比较。返回的比较器,被强转为可序列化的。

public static <K extends Comparable<? super K>, V> Comparator<Map.Entry<K,V>> comparingByKey() 
    return (Comparator<Map.Entry<K, V>> & Serializable)
        (c1, c2) -> c1.getKey().compareTo(c2.getKey());

comparingByKey(Comparator<? super K> cmp)

使用 key 按给定的比较规则 cmp 比较。返回的比较器,被强转为可序列化的。

public static <K, V> Comparator<Map.Entry<K, V>> comparingByKey(Comparator<? super K> cmp) 
    Objects.requireNonNull(cmp);
    return (Comparator<Map.Entry<K, V>> & Serializable)
        (c1, c2) -> cmp.compare(c1.getKey(), c2.getKey());

comparingByValue()

默认使用 vale自然升序 比较。返回的比较器,被强转为可序列化的。

public static <K, V extends Comparable<? super V>> Comparator<Map.Entry<K,V>> comparingByValue() 
    return (Comparator<Map.Entry<K, V>> & Serializable)
        (c1, c2) -> c1.getValue().compareTo(c2.getValue());


comparingByValue(Comparator<? super V> cmp)

使用 value 按给定的比较规则 cmp 比较。返回的比较器,被强转为可序列化的。

public static <K, V> Comparator<Map.Entry<K, V>> comparingByValue(Comparator<? super V> cmp) 
    Objects.requireNonNull(cmp);
    return (Comparator<Map.Entry<K, V>> & Serializable)
        (c1, c2) -> cmp.compare(c1.getValue(), c2.getValue());

比较器

Interface Comparable< T >

https://docs.oracle.com/javase/8/docs/api/java/lang/Comparable.html

访问修饰符&返回类型方法描述
intcompareTo(T o)比较此对象与指定对象的顺序。如果该对象小于、等于或大于指定对象,则分别返回负整数、零或正整数。

默认方法

访问修饰符&返回类型方法描述
voidclear()从此映射中移除所有映射关系(可选操作)。
default Vcompute(K key, BiFunction<? super K,? super V,? extends V> remappingFunction)对给定 K使用映射函数mappingFunction进行更新并返回新值。如果 新值null,执行 remove(key) 并返回 null
defaultVcomputeIfAbsent(K key, Function<? super K,? extends V> mappingFunction)如果值不存在或为null,使用 mappingFunction 的结果赋值,如果赋值成功,返回新值,否则返回 null 。(mappingFunction结果为 null 时直接返 null
defaultVcomputeIfPresent(K key, BiFunction<? super K,? super V,? extends V> remappingFunction)如果值存在非null,使用 mappingFunction 计算新值。如果新值非null更新并返回新值,否则 remove(key) 并返回null
booleancontainsKey(Object key)如果此映射包含指定键的映射关系,则返回 true。
booleancontainsValue(Object value)如果此映射将一个或多个键映射到指定值,则返回 true。
Set<Map.Entry<K,V>>entrySet()返回此映射中包含的映射关系的 Set 视图。
booleanequals(Object o)比较指定的对象与此映射是否相等。
default voidforEach(BiConsumer<? super K,? super V> action)两个入参的消费者,默认按 entrySet 顺序逐个消费。
Vget(Object key)返回指定键所映射的值;如果此映射不包含该键的映射关系,则返回 null。
default VgetOrDefault(Object key, V defaultValue)如果 key 找不到映射的 valuenull也算有)。则返回给定的默认值
inthashCode()返回此映射的哈希码值。
booleanisEmpty()如果此映射未包含键-值映射关系,则返回 true。
SetkeySet()返回此映射中包含的键的 Set 视图。
default Vmerge(K key, V value, BiFunction<? super V,? super V,? extends V> remappingFunction)不存在或为null时用 value 赋值,否则用 mappingFunction 更新。如 mappingFunction 返回null等同于remove
Vput(K key, V value)将指定的值与此映射中的指定键关联(可选操作)。
voidputAll(Map<? extends K,? extends V> m)从指定映射中将所有映射关系复制到此映射中(可选操作)。
default VputIfAbsent(K key, V value)如果值存在非空执行 get(k),否则执行put(k, v)并返回其结果。
Vremove(Object key)如果存在一个键的映射关系,则将其从此映射中移除(可选操作)。
default booleanremove(Object key, Object value)键、值都匹配则删除。
default Vreplace(K key, V value)有对应值就执行替换。
default booleanreplace(K key, V oldValue, V newValue)如果key确实映射到 oldValue 则替换值为newValue
default voidreplaceAll(BiFunction<? super K,? super V,? extends V> function)调用给定函数BiFun,遍历替entryBiFun返回值替换元素的值,直到完成所有或抛异常。
intsize()返回此映射中的键-值映射关系数。
Collectionvalues()返回此映射中包含的值的 Collection 视图。

Java8 开始引入了默认方法概念,允许向接口中添加默认实现。(用来兼容升级接口)
以下都默认方法。

V compute(K key, BiFunction<K, V, V> fun)

  • test
    @Test
    public void computeTest()
        Map<Object, Object> map = new WeakHashMap<>();
        map.put("a", 1);

        Object result = map.compute("a", (k, v) -> k + " : " + v);
        System.out.println("原值:" + result);          // 1
        System.out.println("更新后:" +map);            // a=a : 1

        result = map.compute("b", (k, v) -> null);
        System.out.println("原值:" + result);          //  null
        System.out.println("更新后:" +map);            // a=a : 1


        result = map.compute("a", (k, v) -> null);
        System.out.println("原值:" + result);          // null
        System.out.println("更新后:" +map);            // 
    
  • compute
    default V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) 
    	// 检测给定的 lambda 方法 remappingFunction 如果为 null 就抛锅。
        Objects.requireNonNull(remappingFunction);
        // 先取出旧值缓存。
        V oldValue = get(key);
		// 对旧值应用给定的 lambda 方法算出新值
        V newValue = remappingFunction.apply(key, oldValue);
        // 如果新值为空,则移除原键值对,返回 null
        // 否则新值不为空,则:用新值替换旧值,并返回新值。
        if (newValue == null) 
        	// 新值为空则,返回 null
        	// 但如果原 key 或 value 存在,则需要先删除原键值对,再返回 null
            if (oldValue != null || containsKey(key))  
                remove(key);
                return null;
             else  
                return null;
            
         else 
            put(key, newValue);
            return newValue;
        
    

按理说,新值是否为 null 触发删除逻辑这段不是应该过样写么

		// 不为空,替换,并返回新值
        if (newValue != null) 
            put(key, newValue);
            return newValue;
        
        // 否则新值为空,key存在或旧值不为空,执行删除。
        if (oldValue != null || containsKey(key))  
            remove(key);
         
        // 最后返回 null
        return null;

V computeIfAbsent(K key, Function<K, V> fun)

    @Test
    public void computeIfAbsentTest() 
        Map<Object, Object> map = new WeakHashMap<>();
        map.put("a", 1);

        Object a = map.computeIfAbsent("a", key -> DateUtil.today());
        Object b = map.computeIfAbsent("b", key -> DateUtil.today());
        Object c = map.computeIfAbsent("c", key -> null);

        System.out.println(a);   // 1
        System.out.println(b);   // 2022-11-16
        System.out.println(c);   // null
        System.out.println(map); // a=1, b=2022-11-16
    
  • computeIfAbsent
    default V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) 
        // 检测给定的 lambda 方法 remappingFunction 如果为 null 就抛锅。
        Objects.requireNonNull(mappingFunction);
        // 声明返回变量
        V v;
        // 获取 key 对应的值,如果值存在,直接返回
        // 否则 mappingFunction 生成一个新值填充。并返回新值
        // 如果生成的也是 null 直接返回 null
        if ((v = get(key)) == null) 
            V newValue;
            if ((newValue = mappingFunction.apply(key)) != null) 
                put(key, newValue);
                return newValue;
            
        

        return v;
    

V computeIfPresent(K key, BiFunction<K, V, V> fun)

  • test
    @Test
    public void computeIfPresentTest()
        Map<String, Integer> map = new WeakHashMap<>();
        map.put("a", 1);
        map.put("b", null);

        // 值不为空,替换新值
        Integer result = map.computeIfPresent("a", (k, v) -> 2 );
        System.out.println("原值:" + result);          //  2
        System.out.println("更新后:" +map);            // a=2, b=null

        // 值为 null,啥也不做,直接返回 null
        result = map.computeIfPresent("b", (k, v) -> 666 );
        System.out.println("原值:" + result);          //  null
        System.out.println("更新后:" +map);            // a=2, b=null

        // 按 key 找到值,执行 lambda 得到新值为空,移除键值对
        result = map.computeIfPresent("a", (k, v) -> null );
        System.out.println("原值:" + result);          //  null
        System.out.println("更新后:" +map);            // b=null
    
  • computeIfPresent
    default V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) 
    	// 非空检测,如果为 null 就抛锅。
        Objects.requireNonNull(remappingFunction);
        // 声明临时变量用于存放旧值
        V oldValue;
        // 按 key 获取对应值,并付给 oldValue,如果为空直接返回 null
        // 否则使用给定的 remappingFunction 处理原键值对,得出新值 newValue 
        // 新值不为空:调用 put 修改为 newValue。并返回 newValue
        // 否则移除 键值对。返回 null
        if ((oldValue = get(key)) != null) 
            V newValue = remappingFunction.apply(key, oldValue);
            if (newValue != null) 
                put(key, newValue);
                return newValue;
             else 
                remove(key);
                return null;
            
         else 
            return null;
        
    

void forEach(BiConsumer<K, V> action)

  • test
    @Test
    public void forEachTest()
        Map<String, Integer> map = new WeakHashMap<>();
        map.put("a", 1);
        map.put("b", 2);
        map.forEach((k,v) -> 
            System.out.println( "键="+ k + "; 值="java集合学习笔记(代码片段)

Java集合学习笔记前言开始学习Java的集合,简要的记录一下学习到的东西,仅供自己查阅和复习方便。学习自廖雪峰的Java教程。集合简介Java标准库自带的java.util包提供了集合类:Collection,它是除Map外所有其他集... 查看详情

java集合学习笔记(代码片段)

Java集合学习笔记前言开始学习Java的集合,简要的记录一下学习到的东西,仅供自己查阅和复习方便。学习自廖雪峰的Java教程。集合简介Java标准库自带的java.util包提供了集合类:Collection,它是除Map外所有其他集... 查看详情

尚硅谷_java零基础教程(集合collection:list,set;map)--学习笔记(代码片段)

Java集合一、Java集合框架概述1.理解2.集合框架涉及到的API二、Collection接口中的方法三、Iterator迭代器接口1.理解2.主要方法3.foreach四、Collection子接口一:List接口1.概述2.List接口的常用实现类3.接口方法五、Collection子接口二ÿ... 查看详情

java学习笔记:list,set,map(代码片段)

...,还有很多没加上去。。。未完待续。。。容器也叫集合ArrayList:用数组组成的线性结构LinkedList:用链表组成的线性结构…所有的容器装的是对象,但是容器会把传进去的孤立的值自动装箱成对象,功能强大... 查看详情

java集合学习笔记:hashmap(代码片段)

Java集合学习笔记:HashMapUML简介阅读源码属性字段1.静态属性2.成员属性HashMap结构静态工具方法hash【算法学习】^加>>>减少碰撞comparableClassFor(Objectx)compareComparables(Class<?>kc,Objectk,Objectx)tableSizeFor(intcap)【算法学习】32 查看详情

java集合学习笔记:abstractlist(代码片段)

Java集合学习笔记:AbstractListequals(Objecto)hashCode()indexOf(Objecto)lastIndexOf(Objecto)clear()addAll(intindex,Collection<?extendsE>c)equals(Objecto)ItrListItrSubList参考资料equals(Objecto)实现equa 查看详情

java集合学习笔记:hashmap(代码片段)

Java集合学习笔记:HashMapUML简介阅读源码属性字段1.静态属性2.成员属性静态内部类classNode<K,V>静态工具方法hash(Objectkey)comparableClassFor(Objectx)compareComparables(Class<?>kc,Objectk,Objectx)tableSizeFor(intcap)构造方法H 查看详情

java集合容器篇面试题(上)-王者笔记《收藏版》(代码片段)

...ff08;上)Java基础知识学习总结(下)目录一、集合容器概述1.1什么是集合1.2集合的特点1.3集合和数组的区别  1.4使用集合框架的好处1.5常用的集合类有哪些?1.6List,Set,Map三者的区别和特点?1.7集合... 查看详情

java集合学习笔记:比较器comparablecomparator(代码片段)

Java集合学习笔记:比较器Comparable、ComparatorComparable隐式比较升序(默认)Comparator显示比较Lambda降序Comparator.reverseOrder降序参考资料Comparable隐式比较packagecom.jerry;importlombok.Data;@DatapublicclassHero 查看详情

java集合学习笔记:比较器comparablecomparator(代码片段)

Java集合学习笔记:比较器Comparable、ComparatorComparable隐式比较升序(默认)Comparator显示比较Lambda降序Comparator.reverseOrder降序参考资料Comparable隐式比较packagecom.jerry;importlombok.Data;@DatapublicclassHero 查看详情

java集合学习笔记:arraylist(代码片段)

Java集合学习笔记:ArrayList简介UML常用方法增删改查迭代内部类静态内部类自动扩容逻辑Java7Java8扩容-核心代码移除-核心代码使用建议参考资料简介ArrayList是List接口的大小可变数组的实现。实现了所有可选列表操作,并允... 查看详情

java集合学习笔记:arraylist(代码片段)

Java集合学习笔记:ArrayList简介UML常用方法增删改查迭代内部类静态内部类自动扩容逻辑Java7Java8扩容-核心代码移除-核心代码使用建议参考资料简介ArrayList是List接口的大小可变数组的实现。实现了所有可选列表操作,并允... 查看详情

java集合学习笔记:list(代码片段)

Java集合学习笔记:ListUMLListUML除了过气的Vector直接实现List接口,其他实现都是通过继承AbstractList实现的。List可以看出List在Collection基础增加的一批方法,都是针对索引用的。限定符和类型方法和说明voidadd(intindex,Eeleme... 查看详情

java集合学习笔记:list(代码片段)

Java集合学习笔记:ListUMLListUML除了过气的Vector直接实现List接口,其他实现都是通过继承AbstractList实现的。List可以看出List在Collection基础增加的一批方法,都是针对索引用的。限定符和类型方法和说明voidadd(intindex,Eeleme... 查看详情

java集合学习笔记:iterableiterator(代码片段)

Java集合学习笔记:Iterable、IteratorUMLIterable_可迭代JDK8之前JDK8新增default方法Iterator_迭代器JDK8之前JDK8新增default方法参考资料UML此图内含Collection.uml可在Idea中打开在学习设计模式的时候就有一个"迭代器模式",JDK中提... 查看详情

java集合学习笔记

集合容器结构图:java容器类类库的用途是保存对象,分为两个概念,collection和map。collection保存单一的元素,而map保存相关联的键值对。collection    中基本方法:intsize():获取集合的元素个数booleanadd(Ee):向集合中添... 查看详情

java集合学习笔记:collection(代码片段)

Java集合学习笔记:CollectionUML简介方法和说明JDK8新增`default`方法参考资料UML简介Collection表示包含了一组元素的对象,它定义了一系列用来折腾这些元素的方法。给徒子徒孙们立好了规矩。通常不直接实现这个接口&#... 查看详情

kotlin学习笔记——接口抽象类泛型扩展集合操作符与java互操作性单例(代码片段)

...扩展属性对泛型扩展infix:中缀表达式结合泛型使用集合操作符mapflatMapfilterzip与Java的互操 查看详情