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 的【元数据】。
原文地址:https://www.cnblogs.com/niujifei/p/14750601.html