随笔1 interface Map

时间:2021-05-03 19:37:57

随笔1 interface Map

第一次写笔记就从map开始吧,如上图所示,绿色的是interface,黄色的是abstract class,蓝色的是class,可以看出所有和图相关的接口,抽象类和类的起源都是interface map<K,V>。现在看一下当前Map接口中实现了什么,里面包含了一个内部接口interface Entry<K,V>,声明了14个方法,同时还定义了11个方法(在jdk1.8中,在interface中可以使用default关键字来定义完整的方法)

由于声明的方法都是原来版本jdk已经存在的,比较简单,所以我们从声明的方法开始介绍

  1 public interface Map<K, V> {
  2 
  3     /**
  4      * 方法返回键值对个数,当键值对个数大于Integer.MAX_VALUE
  5      * 时返回Integer.MAX_VALUE
  6      */
  7     int size();
  8     
  9     /**
 10      * 当Map中没有键值对的时候,返回true
 11      */
 12     boolean isEmpty();
 13     
 14     /**
 15      * 当Map中的键包含key的时候返回true,相当于执行了如下语句
 16      * key==null ? k==null : key.equals(k)
 17      * 此处应该注意Map中的键是可以为null的,但是只可以有一个
 18      * 需要注意的是本方法会有两个异常
 19      * ClassCastException当传入的key和本Map中设置的key类型不相容的时候
 20      * NullPointerException当传入的key==null,并且Map中的键没有null的时候
 21      */
 22     boolean containsKey(Object key);
 23     
 24     /**
 25      * 当有多于一个key的value等于传入的value时会返回true
 26      * 相当于执行value==null ? v==null : value.equals(v)
 27      * 可见value也是可以为null的
 28      * 需要注意的是本方法会抛出两个异常
 29      * ClassCastException当传入的值和Map中的值不相容的时候
 30      * NullPointerException当value中没有一个值为null的时候
 31      */
 32     boolean containsValue(Object value);
 33     
 34     /**
 35      * 如果当前的key存在于Map中,会返回对应的value,否则会返回null
 36      * 需要注意的是本方法会有两个异常
 37      * ClassCastException当传入的key和本Map中设置的key类型不相容的时候
 38      * NullPointerException当传入的key==null,并且Map中的键没有null的时候
 39      * 
 40      */
 41     V get(Object key);
 42     
 43     /**
 44      * 当key不存在是会放入新的键值对,当key存在时,会更新key对应的value值
 45      * 本方法会产生四个异常
 46      * UnsupportedOperationException当Map不支持put操作的时候
 47      * ClassCastException当key或者value不相容的时候
 48      * NullPointerException当Map不允许key或者value为null的时候
 49      * IllegalArgumentException如果指定键或值的某些属性阻止将其存储在此映射中
 50      */
 51     V put(K key, V value);
 52     
 53     /**
 54      * 当Map中有这个key的时候,会返回相应的value,否则会返回null
 55      * 本方法会抛出三个异常
 56      * UnsupportedOperationException当Map不支持此操作时
 57      * ClassCastException当key的类型不相容时
 58      * NullPointerException当key是null并且这个Map不允许key为null时
 59      */
 60     V remove(Object key);
 61     
 62     /**
 63      * 将一个Map的所有键值对放入本Map,对于每一个键值对都调用的是put(K key, V value)方法
 64      * 本方法会产生四个异常
 65      * UnsupportedOperationException当Map不支持put操作的时候
 66      * ClassCastException当key或者value不相容的时候
 67      * NullPointerException当Map不允许key或者value为null的时候
 68      * IllegalArgumentException如果指定键或值的某些属性阻止将其存储在此映射中
 69      */
 70     void putAll(Map<? extends K, ? extends V> m);
 71     
 72     /**
 73      * 从Map中移除所有的元素
 74      * 会抛出一个异常
 75      * UnsupportedOperationException当Map不支持本操作的时候
 76      */
 77     void clear();
 78     
 79     /**
 80      * 会以集合的形式返回key,当修改Map的key时会反应在Set中,反之亦然
 81      */
 82     Set<K> keySet();
 83     
 84     /**
 85      * 返回一个Collection集合对于值来说,因为值可以有重复的,所以才选用了Collection
 86      * 同样的对Map修改时,也会反应到Collection上
 87      */
 88     Collection<V> values();
 89     
 90     /**
 91      * 返回一个键值对的集合Entry<K, V>
 92      */
 93     Set<Map.Entry<K, V>> entrySet();
 94     
 95     /**
 96      * 本方法是用来比较两个Map是否相同的
 97      */
 98     boolean equals(Object o);
 99     
100     /**
101      * 本方法是用于返回一个Map的Hash值,本方法要求对Map中的每一个Entry<K,V>进行运算的
102      * 这样保证了当m1.equals(m2)时m1.hashCode()==m2.hashCode()
103      */
104     int hashCode();
105     
106     
107 }

 

接下来我们来看一下内部的接口interface Entry<K,V>的内容

 1 interface Entry<K,V> {
 2         /**
 3          * 返回Entry的key
 4          * IllegalStateException 并不要求实现类必须抛出这个异常,在访问Map中的Entry元素时可能用到,即Entry已经被移除时
 5          */
 6         K getKey();
 7         
 8         /**
 9          * 返回Entry的value
10          * IllegalStateException 并不要求实现类必须抛出这个异常,在访问Map中的Entry元素时可能用到,即Entry已经被移除时
11          */
12         V getValue();
13         
14         /**
15          * 重新设置Entry的value,但是当映射关系被移除时,该方法的行为还未被定义
16          * 抛出五个异常
17          * UnsupportedOperationException如果Map不支持put操作
18          * ClassCastException当与指定类型不相容的时候
19          * NullPointerException当Map不允许出现null而此时设置的值为null的时候
20          * IllegalArgumentException如果当前值的属性不允许它存储在图中
21          * IllegalStateException并不要求实现类必须抛出这个异常,在访问Map中的Entry元素时可能用到,即Entry已经被移除时
22          */
23         V setValue(V value);
24         
25         /**
26          * 当比较对象也是一个Entry并且表达同样的映射关系的时候返回true
27          */
28         boolean equals(Object o);
29         
30         /**
31          * 本方法实现的要求是当e1.equals(e2)时,e1.hashCode()==e2.hashCode()
32          */
33         int hashCode();
34         
35         //从以下开始都是jdk1.8新增的方法,对于jdk1.8的新特性就不再这里分析了,会单写一篇的
36         /**
37          * 本方法会返回一个比较器,用来实现对Entry的key进行比较
38          */
39         public static <K extends Comparable<? super K>, V> Comparator<Map.Entry<K,V>> comparingByKey() {
40             return (Comparator<Map.Entry<K, V>> & Serializable)
41                 (c1, c2) -> c1.getKey().compareTo(c2.getKey());
42         }
43         
44         /**
45          * 本方法返回一个比较器,用来实现对Entry的value进行比较,这里表示返回值同时满足两个接口
46          */
47         public static <K, V extends Comparable<? super V>> Comparator<Map.Entry<K,V>> comparingByValue() {
48             return (Comparator<Map.Entry<K, V>> & Serializable)
49                 (c1, c2) -> c1.getValue().compareTo(c2.getValue());
50         }
51         
52         /**
53          * 这个方法和上两个方法不同之处在于上两个要求K或者V实现Comparable接口,使得本身可以比较
54          * 而这个方法中并没有对K,V有什么要求,而是需要一个已经实现Comparator的接口
55          */
56         public static <K, V> Comparator<Map.Entry<K, V>> comparingByKey(Comparator<? super K> cmp) {
57             Objects.requireNonNull(cmp);
58             return (Comparator<Map.Entry<K, V>> & Serializable)
59                 (c1, c2) -> cmp.compare(c1.getKey(), c2.getKey());
60         }
61         
62         /**
63          * 同上
64          */
65         public static <K, V> Comparator<Map.Entry<K, V>> comparingByValue(Comparator<? super V> cmp) {
66             Objects.requireNonNull(cmp);
67             return (Comparator<Map.Entry<K, V>> & Serializable)
68                 (c1, c2) -> cmp.compare(c1.getValue(), c2.getValue());
69         }
70         
71     }

这里简单解释一下上述代码中jdk1.8的新特性以便使代码容易理解一些,Comparator<Map.Entry<K, V>> & Serializable这里并不是表达与操作,而是返回值同时实现了这两个接口,(c1, c2) -> cmp.compare(c1.getValue(), c2.getValue())是lambda表达式实现了一个函数式接口Comparator的compare方法

最后一部分是Map在jdk1.8中新增的default方法,在jdk1.8中,可以在interface中实现方法了,但是得用default关键字修饰

  1     /**
  2      * 本方法是在普通get方法上增加了一个默认值,防止了得到的value为null的情况
  3      * 抛出两个异常
  4      * ClassCastException当key和Map中要求的key不兼容时
  5      * NullPointerException当Map不支持null为key时
  6      */
  7     default V getOrDefault(Object key, V defaultValue) {
  8         V v;
  9         return (((v = get(key)) != null) || containsKey(key))
 10             ? v
 11             : defaultValue;
 12     }
 13     
 14     /**
 15      * 对Map中的每一个Entry进行一次action包含的操作
 16      * 抛出两个异常
 17      * NullPointerException当action为null时
 18      * ConcurrentModificationException在迭代过程中有元素被移除
 19      */
 20     default void forEach(BiConsumer<? super K, ? super V> action) {
 21         Objects.requireNonNull(action);
 22         for (Map.Entry<K, V> entry : entrySet()) {
 23             K k;
 24             V v;
 25             try {
 26                 k = entry.getKey();
 27                 v = entry.getValue();
 28             } catch(IllegalStateException ise) {
 29                 // this usually means the entry is no longer in the map.
 30                 throw new ConcurrentModificationException(ise);
 31             }
 32             action.accept(k, v);
 33         }
 34     }
 35     
 36     /**
 37      * 对Map中的每个Entry都用function进行操作,返回得到的结果重新设置value
 38      */
 39     default void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
 40         Objects.requireNonNull(function);
 41         for (Map.Entry<K, V> entry : entrySet()) {
 42             K k;
 43             V v;
 44             try {
 45                 k = entry.getKey();
 46                 v = entry.getValue();
 47             } catch(IllegalStateException ise) {
 48                 // this usually means the entry is no longer in the map.
 49                 throw new ConcurrentModificationException(ise);
 50             }
 51 
 52             // ise thrown from function is not a cme.
 53             v = function.apply(k, v);
 54 
 55             try {
 56                 entry.setValue(v);
 57             } catch(IllegalStateException ise) {
 58                 // this usually means the entry is no longer in the map.
 59                 throw new ConcurrentModificationException(ise);
 60             }
 61         }
 62     }
 63     
 64     /**
 65      * 当key对应的value为null的时候,设置新的value值
 66      */
 67     default V putIfAbsent(K key, V value) {
 68         V v = get(key);
 69         if (v == null) {
 70             v = put(key, value);
 71         }
 72 
 73         return v;
 74     }
 75     
 76     /**
 77      * 当key和value与当前map中有完全相同的,就删除该元素,返回true,否则返回false,不做任何操作
 78      */
 79     default boolean remove(Object key, Object value) {
 80         Object curValue = get(key);
 81         if (!Objects.equals(curValue, value) ||
 82             (curValue == null && !containsKey(key))) {
 83             return false;
 84         }
 85         remove(key);
 86         return true;
 87     }
 88     
 89     /**
 90      * 当Map中存在key->oldValue时,替换为key->newValue,返回true,否则返回false,不做任何操作
 91      */
 92     default boolean replace(K key, V oldValue, V newValue) {
 93         Object curValue = get(key);
 94         if (!Objects.equals(curValue, oldValue) ||
 95             (curValue == null && !containsKey(key))) {
 96             return false;
 97         }
 98         put(key, newValue);
 99         return true;
100     }
101     
102     /**
103      * 用新的value替换老的value,并返回老的value,如果key不存在,返回null
104      */
105     default V replace(K key, V value) {
106         V curValue;
107         if (((curValue = get(key)) != null) || containsKey(key)) {
108             curValue = put(key, value);
109         }
110         return curValue;
111     }
112     
113     /**
114      * 传入一个单参数函数,找到key对应的value,如果value==null,然后对key进行重新计算,得到新的value,返回新的value。否则返回null
115      */
116     default V computeIfAbsent(K key,
117             Function<? super K, ? extends V> mappingFunction) {
118         Objects.requireNonNull(mappingFunction);
119         V v;
120         if ((v = get(key)) == null) {
121             V newValue;
122             if ((newValue = mappingFunction.apply(key)) != null) {
123                 put(key, newValue);
124                 return newValue;
125             }
126         }
127 
128         return v;
129     }
130     
131     /**
132      * 如果Map中存在key,并且对应的value!=null的时候,用传入的两个参数的函数进行重新计算,得到新的value,如果新的value==null
133      * 就删除这个键值对,返回null,否则覆盖旧值,返回新的value,如果key不存在,也返回null
134      */
135     default V computeIfPresent(K key,
136             BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
137         Objects.requireNonNull(remappingFunction);
138         V oldValue;
139         if ((oldValue = get(key)) != null) {
140             V newValue = remappingFunction.apply(key, oldValue);
141             if (newValue != null) {
142                 put(key, newValue);
143                 return newValue;
144             } else {
145                 remove(key);
146                 return null;
147             }
148         } else {
149             return null;
150         }
151     }
152     
153     /**
154      * 通过原来的键值对,计算出一个新的值,如果新的值不为空,重新设置键值对,并返回新的value,否则删除原来的键值对,返回null
155      */
156     default V compute(K key,
157             BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
158         Objects.requireNonNull(remappingFunction);
159         V oldValue = get(key);
160 
161         V newValue = remappingFunction.apply(key, oldValue);
162         if (newValue == null) {
163             // delete mapping
164             if (oldValue != null || containsKey(key)) {
165                 // something to remove
166                 remove(key);
167                 return null;
168             } else {
169                 // nothing to do. Leave things as they were.
170                 return null;
171             }
172         } else {
173             // add or replace old mapping
174             put(key, newValue);
175             return newValue;
176         }
177     }
178     
179     /**
180      * 将旧的value和新的value进行混合计算,得到另一个value,如果这个value不为空,就和原来的key形成映射关系,返回新的value,
181      * 否则移除原来的键值对,返回null
182      */
183     default V merge(K key, V value,
184             BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
185         Objects.requireNonNull(remappingFunction);
186         Objects.requireNonNull(value);
187         V oldValue = get(key);
188         V newValue = (oldValue == null) ? value :
189                    remappingFunction.apply(oldValue, value);
190         if(newValue == null) {
191             remove(key);
192         } else {
193             put(key, newValue);
194         }
195         return newValue;
196     }

这些方法中出现了比较陌生的BiConsumer,BiFunction和Function这三个接口,都是在java.util.function包下的新接口,可以把他们看做一个函数去理解就好了。BiConsumer

是接受两个参数,没有计算的返回值。BiFunction是接受两个参数返回一个参数。Function是接受一个参数返回一个参数。