Java源码阅读–Map
结构概览
Map接口由内部类Entry和众多方法组成,具体图下
Entry
Entry内的默认方法:
- comparingByKey
public static <K extends Comparable<? super K>, V> Comparator<Map.Entry<K,V>> comparingByKey() {
// 这是强制类型转换,转换成可序列化的Comparator<Map.Entry<K, V>>对象。&的意思是且的意思
return (Comparator<Map.Entry<K, V>> & Serializable)
(c1, c2) -> c1.getKey().compareTo(c2.getKey());
}
这个方法看似不知所云,实际上很简单,返回一个比较俩Entry的key值得Comparator。有些不怎么见得语法是阅读得拦路虎,比如 Comparator<Map.Entry<K, V>> & Serializable ,给爷也整懵了,互联网还是个好东西啊,“这是强制类型转换,转换成可序列化的Comparator<Map.Entry<K, V>>对象。&的意思是且的意思”
样例:
Map<Integer,Integer> map1 = new HashMap<>();
map1.put(1,1);
map1.put(2,2);
map1.put(3,3);
Map<Integer,Integer> map2 = new HashMap<>();
map2.put(1,1);
map2.put(2,2);
map2.put(3,3);
// 获取比较俩Entry的key的Comparator
Comparator<Map.Entry<Integer, Integer>> entryComparator = Map.Entry.comparingByKey();
// 构造俩Entry的List,为了方便取Entry
List<Map.Entry> entries1 = new ArrayList<>(map1.entrySet());
List<Map.Entry> entries2 = new ArrayList<>(map2.entrySet());
System.out.println(entryComparator.compare(entries1.get(0), entries2.get(0))); // 相当于比较1,1
System.out.println(entryComparator.compare(entries1.get(0), entries2.get(1))); // 相当于比较1,2
System.out.println(entryComparator.compare(entries1.get(1), entries2.get(0))); // 相当于比较2,1
输出:
0
-1
1
- comparingByValue
public static <K, V extends Comparable<? super V>> Comparator<Map.Entry<K,V>> comparingByValue() {
return (Comparator<Map.Entry<K, V>> & Serializable)
(c1, c2) -> c1.getValue().compareTo(c2.getValue());
}
与上个方法类似,只是比较了value
- comparingByKey
public static <K, V> Comparator<Map.Entry<K, V>> comparingByKey(Comparator<? super K> cmp) {
Objects.requireNonNull(cmp);
return (Comparator<Map.Entry<K, V>> & Serializable)
(c1, c2) -> cmp.compare(c1.getKey(), c2.getKey());
}
比较Entry的key,不过是按照传入的规则进行比较
样例:
Map<String,Integer> map1 = new HashMap<>();
map1.put("1",1);
map1.put("2",2);
map1.put("3",3);
Map<String,Integer> map2 = new HashMap<>();
map2.put("1",1);
map2.put("2",2);
map2.put("3",3);
Comparator<Map.Entry<String, Integer>> entryComparator = Map.Entry.comparingByKey((c1, c2) -> {
if (c1.equals(c2)) {
System.out.println(c1 + "与" + c2 + "相等");
} else {
System.out.println(c1 + "与" + c2 + "不相等");
return -1;
}
return 0;
});
List<Map.Entry> entries1 = new ArrayList<>(map1.entrySet());
List<Map.Entry> entries2 = new ArrayList<>(map2.entrySet());
System.out.println(entryComparator.compare(entries1.get(0), entries2.get(0))); // 相当于比较1,1
System.out.println(entryComparator.compare(entries1.get(0), entries2.get(1))); // 相当于比较1,2
System.out.println(entryComparator.compare(entries1.get(1), entries2.get(0))); // 相当于比较2,1
输出:
1与1相等
0
1与2不相等
-1
2与1不相等
-1
- comparingByValue
public static <K, V> Comparator<Map.Entry<K, V>> comparingByValue(Comparator<? super V> cmp) {
Objects.requireNonNull(cmp);
return (Comparator<Map.Entry<K, V>> & Serializable)
(c1, c2) -> cmp.compare(c1.getValue(), c2.getValue());
}
换成比较value,没啥好说的
Default方法阅读
作为一个接口,Map的大部分方法需要实现类去实现,但其也有部分方法有着默认实现
首先看一下Map类的“头”:
有着俩泛型 K 和 V ,记住就行
- getOrDefault
default V getOrDefault(Object key, V defaultValue) {
V v;
return (((v = get(key)) != null) || containsKey(key))
? v
: defaultValue;
}
方法很简单,入参 key 和自定义 defaultValue,通过判定 get(key) 是否为null(如果不为null就一定存在此key和对应value,如果为null则不确定,所以需要判定是否存在此key)和 containsKey(key),来返回具体value或传入的默认值。
- forEach
default void forEach(BiConsumer<? super K, ? super V> action) {
Objects.requireNonNull(action);
for (Map.Entry<K, V> entry : entrySet()) {
K k;
V v;
try {
k = entry.getKey();
v = entry.getValue();
} catch(IllegalStateException ise) {
// this usually means the entry is no longer in the map.
throw new ConcurrentModificationException(ise);
}
action.accept(k, v);
}
}
forEach方法遍历Map内的每个Entry,也就是每个键值对,我们可以传入指定操作,操作每个键值对(从源码上看不支持写入)
样例:
Map<Integer,Integer> map = new HashMap<>();
map.put(1,1);
map.put(2,2);
map.put(3,3);
for (Map.Entry entry : map.entrySet()) {
System.out.println("key: "+entry.getKey()+" "+"value: "+entry.getValue());
}
System.out.println();
// 使用forEach方法,输出k,v键值对
map.forEach((k,v) -> {
System.out.println("key: "+(k+1)+" "+"value: "+(v+1));
});
输出:
key: 1 value: 1
key: 2 value: 2
key: 3 value: 3
key: 2 value: 2
key: 3 value: 3
key: 4 value: 4
- replaceAll
default void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
Objects.requireNonNull(function);
for (Map.Entry<K, V> entry : entrySet()) {
K k;
V v;
try {
k = entry.getKey();
v = entry.getValue();
} catch(IllegalStateException ise) {
// this usually means the entry is no longer in the map.
throw new ConcurrentModificationException(ise);
}
// ise thrown from function is not a cme.
v = function.apply(k, v);
try {
entry.setValue(v);
} catch(IllegalStateException ise) {
// this usually means the entry is no longer in the map.
throw new ConcurrentModificationException(ise);
}
}
}
replaceAll方法类似于forEach方法,但是replaceAll方法支持写入,正如方法名所描述的,此方法可以依据传入的特定操作替换所有 k,v 键值对中的value值。
样例:
Map<Integer,Integer> map = new HashMap<>();
map.put(1,1);
map.put(2,2);
map.put(3,3);
for (Map.Entry entry : map.entrySet()) {
System.out.println("key: "+entry.getKey()+" "+"value: "+entry.getValue());
}
System.out.println();
// 使用replaceAll方法替换value为k+v的值
map.replaceAll((k,v) -> k+v);
// 使用forEach方法,输出k,v键值对
map.forEach((k,v) -> {
System.out.println("key: "+k+" "+"value: "+v);
});
输出
key: 1 value: 1
key: 2 value: 2
key: 3 value: 3
key: 1 value: 2
key: 2 value: 4
key: 3 value: 6
- putIfAbsent
default V putIfAbsent(K key, V value) {
V v = get(key);
if (v == null) {
v = put(key, value);
}
return v;
}
这个方法就不要太简单了哈,看不懂的出门左拐看Java基础去
- remove
default boolean remove(Object key, Object value) {
Object curValue = get(key);
if (!Objects.equals(curValue, value) ||
(curValue == null && !containsKey(key))) {
return false;
}
remove(key);
return true;
}
注意一下其中的 if 语句判断的顺序就好了,按照自然思维,应该是先判断是否存在key,然后判断value值是否相等。
这里的做法恰恰相反,原因是 get(key) 如果不存在 key 则会返回null,然后拿去和传入的value做对比,假设正常人传入正常值,那么只需要一次判断。讲实话,我都不认为需要第二个判断。。。
- replace
default boolean replace(K key, V oldValue, V newValue) {
Object curValue = get(key);
if (!Objects.equals(curValue, oldValue) ||
(curValue == null && !containsKey(key))) {
return false;
}
put(key, newValue);
return true;
}
与remove类似,不予赘述
- replace
default V replace(K key, V value) {
V curValue;
if (((curValue = get(key)) != null) || containsKey(key)) {
curValue = put(key, value);
}
return curValue;
}
key 存在则替换
- computeIfAbsent
default V computeIfAbsent(K key,
Function<? super K, ? extends V> mappingFunction) {
Objects.requireNonNull(mappingFunction);
V v;
if ((v = get(key)) == null) {
V newValue;
if ((newValue = mappingFunction.apply(key)) != null) {
put(key, newValue);
return newValue;
}
}
return v;
}
如果不存在key,则通过传入的特定操作,得到value值,并将此key.,value添加进map中
样例:
Map<Integer,Integer> map = new HashMap<>();
map.put(1,1);
map.put(2,2);
map.put(3,3);
// 使用forEach方法,输出k,v键值对
map.forEach((k,v) -> {
System.out.println("key: "+k+" "+"value: "+v);
});
System.out.println();
map.computeIfAbsent(4, k -> k+1 ); // 如果key=4不存在,则添加(4,5)键值对
// 使用forEach方法,输出k,v键值对
map.forEach((k,v) -> {
System.out.println("key: "+k+" "+"value: "+v);
});
输出
key: 1 value: 1
key: 2 value: 2
key: 3 value: 3
key: 1 value: 1
key: 2 value: 2
key: 3 value: 3
key: 4 value: 5
- computeIfPresent
default V computeIfPresent(K key,
BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
Objects.requireNonNull(remappingFunction);
V oldValue;
if ((oldValue = get(key)) != null) {
V newValue = remappingFunction.apply(key, oldValue); // calculate the newValue from the key and oldValue
if (newValue != null) {
put(key, newValue);
return newValue;
} else {
remove(key); // if newValue is null,remove the key
return null;
}
} else {
return null;
}
}
如果key对应的value不为null,那么就通过key值和旧的value值按照传入的计算方法算出新的value;如果新的value不为null那么就put新的key,value键值对并返回新的value,否则删除key,返回null
样例:
Map<Integer,Integer> map = new HashMap<>();
map.put(1,1);
map.put(2,2);
map.put(3,3);
// 使用forEach方法,输出k,v键值对
printMap(map);
System.out.println("======");
// 如果存在key,则保存新的value=key+odlValue=6
System.out.println(map.computeIfPresent(3, Integer::sum));
System.out.println("======");
// 使用forEach方法,输出k,v键值对
printMap(map);
System.out.println("======");
// 返回null,并删除key=3
System.out.println(map.computeIfPresent(3, (k,v) -> null));
System.out.println("======");
// 使用forEach方法,输出k,v键值对
printMap(map);
输出
key: 1 value: 1
key: 2 value: 2
key: 3 value: 3
======
6
======
key: 1 value: 1
key: 2 value: 2
key: 3 value: 6
======
null
======
key: 1 value: 1
key: 2 value: 2
- compute
default V compute(K key,
BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
Objects.requireNonNull(remappingFunction);
V oldValue = get(key);
V newValue = remappingFunction.apply(key, oldValue);
if (newValue == null) {
// delete mapping
if (oldValue != null || containsKey(key)) {
// something to remove
remove(key);
return null;
} else {
// nothing to do. Leave things as they were.
return null;
}
} else {
// add or replace old mapping
put(key, newValue);
return newValue;
}
}
和compute类似,不予赘述
- merge
default V merge(K key, V value,
BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
Objects.requireNonNull(remappingFunction);
Objects.requireNonNull(value);
V oldValue = get(key);
V newValue = (oldValue == null) ? value :
remappingFunction.apply(oldValue, value); // get the newValue from the passed in value and oldValue
if(newValue == null) {
remove(key);
} else {
put(key, newValue);
}
return newValue;
}
和compute方法类似,只是是通过旧的value值和传入的value值得出新的value,如果新的value不为null那么就put新的key,value键值对并返回新的value,否则删除key,返回null
好了,Map接口的默认方法就是这些了。我自己看完后觉得收获满满。希望你也一样。