一、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 }
七、总结