第一次写笔记就从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是接受一个参数返回一个参数。