• Java 集合:(十八) Map接口


    一、Map 接口概述

      1、Map 与 Collection 并列存在。Collection是单列的容器,Map是双列的容器,Map用于保存具有映射关系的数据:key-value;

      2、Map 是一个接口,它表示一种 "键-值(key-value)" 映射的对象(Entry),其中键是不重复的(值可以重复),且最多映射到一个值(可以理解为“映射”或者“字典”)。

      3、Map 中的 key 和 value 都可以是任何引用类型的数据,常用 String 类作为 Map 的“键”;

      4、Map 中的 key 用Set来存放,不允许重复,即同一个 Map 对象所对应的类,重写hashCode()和equals()方法

      5、key 和 value 之间存在单向一对一关系,即通过指定的 key 总能找到唯一的、确定的 value;

      6、Map接口的常用实现类:HashMap、TreeMap、LinkedHashMap和Properties。其中,HashMap是 Map 接口使用频率最高的实现类;

      7、Map 接口继承树

        

      8、Map 的继承结构如下:

        

     

    二、Map 接口中存储 key-value 的特点

      1、key 是不可以重复还是无序的,values 是可以重复的,并且 key 与 value 存在一一的映射关系。

        

      

      2、key 和 value 组成了一个个的 Entry,Entry 无序,不可重复的。

      3、Map中的key:无序的、不可重复的,使用Set存储所有的key  ---> key所在的类要重写equals()和hashCode() (以HashMap为例)

      4、Map中的value:无序的、可重复的,使用Collection存储所有的value --->value所在的类要重写equals()

      5、一个键值对:key-value构成了一个Entry对象。Map中的entry:无序的、不可重复的,使用Set存储所有的entry

    三、Map 的方法列表

       

    四、Map 常用方法

      1、常用方法

    // 将键-值对存入 Map,若 key 对应的 value 已存在,则将其替换
    // 返回原先 key 对应的 value(若不存在,返回 null)
    V put(K key, V value);
    
    
    // 将指定 Map 中的所有元素拷贝到本 Map 中
    void putAll(Map<? extends K, ? extends V> m);
    
    
    // 返回本 Map 中所有 key 的 Set 视图
    Set<K> keySet();
    
    
    // 返回本 Map 中所有 value 的 Collection 视图
    Collection<V> values();
    
    
    // 返回本 Map 中所有 Entry 的 Set 视图
    // 其中 Entry 是 Map 内部的一个接口,可以理解为 Map 的“元数据”
    Set<Map.Entry<K, V>> entrySet();
    

        (1)添加、删除、修改操作

    Object put(Object key,Object value):将指定key-value添加到(或修改)当前map对象中
    void putAll(Map m):将m中的所有key-value对存放到当前map中 
    Object remove(Object key):移除指定key的key-value对,并返回value
    void clear():清空当前map中的所有数据
    

      

         (2)元素查询的操作

    Object get(Object key):获取指定key对应的value
    boolean containsKey(Object key):是否包含指定的key
    boolean containsValue(Object value):是否包含指定的value
    int size():返回map中key-value对的个数
    boolean isEmpty():判断当前map是否为空
    boolean equals(Object obj):判断当前map和参数对象obj是否相等
    

      

         (3)元视图操作的方法

    Set keySet():返回所有key构成的Set集合
    Collection values():返回所有value构成的Collection集合
    Set entrySet():返回所有key-value对构成的Set集合
    

      

      2、JDK8新增方法

      1     // 获取 key 对应的 value,若 value 为 null,则返回 defaultValue
      2     default V getOrDefault(Object key, V defaultValue) {
      3         V v;
      4         return (((v = get(key)) != null) || containsKey(key))
      5                 ? v
      6                 : defaultValue;
      7     }
      8 
      9 
     10     // 遍历 Map 中的元素
     11     default void forEach(BiConsumer<? super K, ? super V> action) {
     12         Objects.requireNonNull(action);
     13         for (Map.Entry<K, V> entry : entrySet()) {
     14             K k;
     15             V v;
     16             try {
     17                 k = entry.getKey();
     18                 v = entry.getValue();
     19             } catch(IllegalStateException ise) {
     20                 // this usually means the entry is no longer in the map.
     21                 throw new ConcurrentModificationException(ise);
     22             }
     23             action.accept(k, v);
     24         }
     25     }
     26 
     27 
     28     // 通过给定的函数计算出新的 Entry 替换所有旧的 Entry
     29     default void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
     30         Objects.requireNonNull(function);
     31         for (Map.Entry<K, V> entry : entrySet()) {
     32             K k;
     33             V v;
     34             try {
     35                 k = entry.getKey();
     36                 v = entry.getValue();
     37             } catch(IllegalStateException ise) {
     38                 // this usually means the entry is no longer in the map.
     39                 throw new ConcurrentModificationException(ise);
     40             }
     41             // ise thrown from function is not a cme.
     42             v = function.apply(k, v);
     43             try {
     44                 entry.setValue(v);
     45             } catch(IllegalStateException ise) {
     46                 // this usually means the entry is no longer in the map.
     47                 throw new ConcurrentModificationException(ise);
     48             }
     49         }
     50     }
     51 
     52 
     53     // 若 key 对应的 value 不存在,则把 key-value 存入 Map,否则无操作
     54     default V putIfAbsent(K key, V value) {
     55         V v = get(key);
     56         if (v == null) {
     57             v = put(key, value);
     58         }
     59         return v;
     60     }
     61 
     62 
     63     // 若 key 对应的值等于 value,则移除 key;否则无操作
     64     default boolean remove(Object key, Object value) {
     65         Object curValue = get(key);
     66         if (!Objects.equals(curValue, value) ||
     67                 (curValue == null && !containsKey(key))) {
     68             return false;
     69         }
     70         remove(key);
     71         return true;
     72     }
     73 
     74 
     75     // 若 key 对应的值等于 oldValue,则将其替换为 newValue;否则无操作
     76     default boolean replace(K key, V oldValue, V newValue) {
     77         Object curValue = get(key);
     78         if (!Objects.equals(curValue, oldValue) ||
     79                 (curValue == null && !containsKey(key))) {
     80             return false;
     81         }
     82         put(key, newValue);
     83         return true;
     84     }
     85 
     86 
     87 // Map 中存在 key 时,将 key-value 存入,相当于:
     88 /*
     89   if (map.containsKey(key)) {
     90       return map.put(key, value);
     91   } else
     92       return null;
     93   }
     94 */
     95     default V replace(K key, V value) {
     96         V curValue;
     97         if (((curValue = get(key)) != null) || containsKey(key)) {
     98             curValue = put(key, value);
     99         }
    100         return curValue;
    101     }
    102 
    103 
    104 // 当 key 对应的 value 不存在时,使用给定的函数计算得出 newValue
    105 // 并将 key-newValue 存入 Map
    106     default V computeIfAbsent(K key,
    107                               Function<? super K, ? extends V> mappingFunction) {
    108         Objects.requireNonNull(mappingFunction);
    109         V v;
    110         if ((v = get(key)) == null) {
    111             V newValue;
    112             if ((newValue = mappingFunction.apply(key)) != null) {
    113                 put(key, newValue);
    114                 return newValue;
    115             }
    116         }
    117         return v;
    118     }
    119 
    120 
    121 // 当 key 对应的 value 存在时,使用给定的函数计算得出 newValue,
    122 // 当 newValue 不为 null 时将 key-newValue 存入 Map;否则移除 key
    123     default V computeIfPresent(K key,
    124                                BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
    125         Objects.requireNonNull(remappingFunction);
    126         V oldValue;
    127         if ((oldValue = get(key)) != null) {
    128             V newValue = remappingFunction.apply(key, oldValue);
    129             if (newValue != null) {
    130                 put(key, newValue);
    131                 return newValue;
    132             } else {
    133                 remove(key);
    134                 return null;
    135             }
    136         } else {
    137             return null;
    138         }
    139     }
    140 
    141 
    142 // 根据 key 和其对应的 oldValue,使用给定的函数计算出 newValue
    143 // 若 newValue 为 null
    144 //   若 oldValue 不为空或 key 存在,则删除 key-oldValue
    145 //   否则无操作
    146 // 若 newValue 不为 null,用 newValue 替换 oldValue
    147     default V compute(K key,
    148                       BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
    149         Objects.requireNonNull(remappingFunction);
    150         V oldValue = get(key);
    151         V newValue = remappingFunction.apply(key, oldValue);
    152         if (newValue == null) {
    153             // delete mapping
    154             if (oldValue != null || containsKey(key)) {
    155                 // something to remove
    156                 remove(key);
    157                 return null;
    158             } else {
    159                 // nothing to do. Leave things as they were.
    160                 return null;
    161             }
    162         } else {
    163             // add or replace old mapping
    164             put(key, newValue);
    165             return newValue;
    166         }
    167     }
    168 
    169 
    170     default V merge(K key, V value,
    171                     BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
    172         Objects.requireNonNull(remappingFunction);
    173         Objects.requireNonNull(value);
    174         V oldValue = get(key);
    175         V newValue = (oldValue == null) ? value :
    176                 remappingFunction.apply(oldValue, value);
    177         if(newValue == null) {
    178             remove(key);
    179         } else {
    180             put(key, newValue);
    181         }
    182         return newValue;
    183     }

    注意:1.8中新增的几个方法看着比较复杂,但有些方法实质上相当于对一些 if...else 语句的封装,利用 lambda 表达式可以让代码更简洁。

      3、Map的遍历方法

        (1)方式一:遍历所有的key集:keySet()

        (2)方式二:遍历所有的value集:values()

        (3)方式二:遍历所有的key-value

          测试代码:

     1     @Test
     2     public void test(){
     3         Map map = new HashMap();
     4         map.put("AA",123);
     5         map.put(45,1234);
     6         map.put("BB",56);
     7 
     8         //遍历所有的key集:keySet()
     9         Set set = map.keySet();
    10             Iterator iterator = set.iterator();
    11             while(iterator.hasNext()){
    12                 System.out.println(iterator.next());
    13         }
    14         System.out.println();
    15         //遍历所有的value集:values()
    16         Collection values = map.values();
    17         for(Object obj : values){
    18             System.out.println(obj);
    19         }
    20         System.out.println();
    21         //遍历所有的key-value
    22         //方式一:entrySet()
    23         Set entrySet = map.entrySet();
    24         Iterator iterator1 = entrySet.iterator();
    25         while (iterator1.hasNext()){
    26             Object obj = iterator1.next();
    27             //entrySet集合中的元素都是entry
    28             Map.Entry entry = (Map.Entry) obj;
    29             System.out.println(entry.getKey() + "---->" + entry.getValue());
    30 
    31         }
    32         System.out.println();
    33         //方式二:
    34         Set keySet = map.keySet();
    35         Iterator iterator2 = keySet.iterator();
    36         while(iterator2.hasNext()){
    37             Object key = iterator2.next();
    38             Object value = map.get(key);
    39             System.out.println(key + "=====" + value);
    40         }
    41     }

    五、常见实现类的简单对比

      1、Map:双列数据,存储key-value对的数据 
      2、HashMap:作为Map的主要实现类;线程不安全的,效率高;存储 null 的 key 和 value;
      3、LinkedHashMap:保证在遍历 map 元素时,可以按照添加的顺序实现遍历。
        原因:在原有的HashMap底层结构基础上,添加了一对指针,指向前一个和后一个元素。
        对于频繁的遍历操作,此类执行效率高于HashMap。
      4、TreeMap:保证按照添加的 key-value 对进行排序,实现排序遍历。此时考虑 key 的自然排序或定制排序
        TreeMap 底层使用红黑树
      5、Hashtable:作为古老的实现类;线程安全的,效率低;不能存储 null 的 key 和 value
      6、Properties:常用来处理配置文件。key 和 value 都是 String类型

    六、Entry 接口

      1、Entry 接口

        Map 接口内部还定义了一个 Entry(上面已经出现),它其实相当于 Map 内存存储的【元数据】,也就是 键-值(key-value)映射。

        方法列表如下:

          

      2、Entry 接口JDK8新增接口

     1     // 返回一个比较器,它以自然顺序比较 Entry 的 key
     2     public static <K extends Comparable<? super K>, V> Comparator<Map.Entry<K,V>> comparingByKey() {
     3         return (Comparator<Map.Entry<K, V>> & Serializable)
     4                 (c1, c2) -> c1.getKey().compareTo(c2.getKey());
     5     }
     6 
     7 
     8     // 返回一个比较器,它以自然顺序比较 Entry 的 value
     9     public static <K, V extends Comparable<? super V>> Comparator<Map.Entry<K,V>> comparingByValue() {
    10         return (Comparator<Map.Entry<K, V>> & Serializable)
    11                 (c1, c2) -> c1.getValue().compareTo(c2.getValue());
    12     }
    13 
    14 
    15     // 返回一个比较器,它使用给定的 Comparator 比较 Entry 的 key
    16     public static <K, V> Comparator<Map.Entry<K, V>> comparingByKey(Comparator<? super K> cmp) {
    17         Objects.requireNonNull(cmp);
    18         return (Comparator<Map.Entry<K, V>> & Serializable)
    19                 (c1, c2) -> cmp.compare(c1.getKey(), c2.getKey());
    20     }
    21 
    22 
    23     // 返回一个比较器,它使用给定的 Comparator 比较 Entry 的 value
    24     public static <K, V> Comparator<Map.Entry<K, V>> comparingByValue(Comparator<? super V> cmp) {
    25         Objects.requireNonNull(cmp);
    26         return (Comparator<Map.Entry<K, V>> & Serializable)
    27                 (c1, c2) -> cmp.compare(c1.getValue(), c2.getValue());
    28     }

    七、总结

    1、Map 接口虽然没有继承自 Collection 接口,但也是 JCF(Java Collections FrameWork)的一部分;
    2、Map 存储的是键-值(key-value)映射结构的对象;
    3、Entry 接口定义在其内部,它是真正定义键-值映射的结构,相当于 Map 的【元数据】。
  • 相关阅读:
    ADO.NET基础学习 二(Command对象)
    如何使ElementUI中的el-dropdown传入多参数
    Vue router Element 重复点击导航路由报错解决方法
    vue-svgicon基本使用
    js 两个相等的数组,修改其中一个怎么做到不改变另外一个
    LocalStorage存储JSON对象
    js取整数、取余数的方法
    JS正则截取两个字符串之间及字符串前后内容的方法
    Vuetify 表单规则验证
    JS正则表达式
  • 原文地址:https://www.cnblogs.com/niujifei/p/14750601.html
Copyright © 2020-2023  润新知