Map中經常被忽略但又非常好用的方法
1. 簡介
map是我們日常開發中常會的集合類之一, 但是我們除了常用的get和put之外,其他的方法好像很少會用到,接下來我們就介紹一下幾個經常被忽略但又很好用的方法.
2. Quick Start
2.1 數據準備
創建一個map對象, 并聲明幾個用于測試的user對象
Map<Integer, User> hashMap = Maps.newHashMap();
User zhangsan = new User(1, "張三");
User lisi = new User(2, "李四");
User zhangtieniu = new User(3, "張鐵牛");
2.2 重溫put
// hashmap put (添加/更新元素)
@Test
public void put() {
User test = hashMap.put(null, null);
User user = hashMap.put(1, null);
User user1 = hashMap.put(1, zhangsan);
User user2 = hashMap.put(1, lisi);
User user3 = hashMap.put(null, zhangsan);
User user4 = hashMap.put(null, lisi);
User user5 = hashMap.get(null);
log.info("map: {}", hashMap);
log.info("user: {}, user1: {}, user2: {}, user3: {}, user4: {}, user5: {}", user, user1, user2, user3, user4, user5);
//map: {null=User(id=2, name=李四), 1=User(id=2, name=李四)}
//user: null, user1: null, user2: User(id=1, name=張三), user3: null, user4: User(id=1, name=張三), user5: User(id=2, name=李四)
}
- key和value可以為null (hashmap 和 linkedhashmap)
- 使用null可以正常的覆蓋和獲取元素
- put可以直接新增or覆蓋已有的元素
- put方法返回對應key的oldValue,如果沒有oldValue則返回null
2.3 getOrDefault
// getOrDefault(Object key, V defaultValue) (獲取/返回默認值)
@Test
public void getOrDefault() {
hashMap.put(1, zhangsan);
hashMap.put(2, null);
final User user1 = hashMap.get(1);
final User user2 = hashMap.getOrDefault(2, lisi);
final User user3 = hashMap.getOrDefault(3, zhangtieniu);
log.info("map: {}", hashMap);
//map: {1=User(id=1, name=張三), 2=null}
log.info("user1: {}, user2: {}, user3: {}", user1, user2, user3);
//user1: User(id=1, name=張三), user2: null, user3: User(id=3, name=張鐵牛)
}
-
當map中沒有對應的key時, 返回對應的defaultValue
注意: 如果map中存在對應的key, 但是對應的
value == null時, 返回的是null, 而不是defaultValue
源碼如下:
default V getOrDefault(Object key, V defaultValue) {
V v;
return (((v = get(key)) != null) || containsKey(key))
? v
: defaultValue;
}
2.4 putIfAbsent
// putIfAbsent(K key, V value) (如果不存在則添加)
@Test
public void putIfAbsent() {
hashMap.put(1, null);
User user1 = hashMap.putIfAbsent(1, zhangsan);
User user2 = hashMap.putIfAbsent(2, lisi);
User user3 = hashMap.putIfAbsent(2, zhangtieniu);
log.info("map: {}", hashMap);
log.info("user1: {}, user2: {}, user3: {}", user1, user2, user3);
//map: {1=User(id=1, name=張三), 2=User(id=2, name=李四)}
//user1: null, user2: null, user3: User(id=2, name=李四)
}
- 如果指定的key對應的value不為null時(
oldValue != null) : 不覆蓋 & 返回oldValue - 當指定key的value不存在時(
oldValue == null) : 添加元素 & 返回oldValue
可以理解為 當指定key的value不存在時, 才去put, 否則不添加
源碼如下:
default V putIfAbsent(K key, V value) {
V v = get(key);
if (v == null) {
v = put(key, value);
}
return v;
}
2.5 compute
// compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) (計算)
@Test
public void compute() {
hashMap.put(1, zhangsan);
User user1 = hashMap.compute(1, (k, oldValue) -> lisi);
log.info("map: {}, user1: {}", hashMap, user1);
//map: {1=User(id=2, name=李四)}, user1: User(id=2, name=李四)
User user2 = hashMap.compute(1, (k, oldValue) -> null);
log.info("map: {}, user2: {}", hashMap, user2);
//map: {}, user2: null
}
remappingFunction返回值 != null: 覆蓋oldValue & 返回newValueremappingFunction返回值 == null: 刪除對應元素 & 返回null
可以理解為 使用remappingFunction的返回值覆蓋對應key的舊值, 當remappingFunction返回值為null時, 會直接將當前元素移除掉
源碼如下:
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;
}
}
2.6 computeIfAbsent
// computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) (不存在則計算)
@Test
public void computeIfAbsent() {
User user = hashMap.computeIfAbsent(1, k -> zhangsan);
User user1 = hashMap.computeIfAbsent(1, k -> lisi);
User user2 = hashMap.computeIfAbsent(2, k -> null);
log.info("map: {}, user:{}, user1: {}, user2:{}", hashMap, user, user1, user2);
//map: {1=User(id=1, name=張三)}, user:User(id=1, name=張三), user1: User(id=1, name=張三), user2:null
}
oldValue != null: 不覆蓋 & 返回oldValueoldValue == null && mappingFunction返回值 != null: 添加元素 & 返回newValueoldValue == null && mappingFunction返回值 == null: 不覆蓋 & 返回null
可以理解為 當指定key的value不存在時, 才使用mappingFunction的返回值覆蓋對應key的舊值, 如果key對應value存在或者mappingFunction的返回值為null時, 則不覆蓋
源碼如下:
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;
}
2.7 computeIfPresent
// computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) (存在則計算)
@Test
public void computeIfPresent() {
hashMap.put(1, zhangsan);
User user1 = hashMap.computeIfPresent(1, (k,oldValue) -> lisi);
User user2 = hashMap.computeIfPresent(3, (k,oldValue) -> zhangtieniu);
log.info("map: {}, user1: {}, user2: {}", hashMap, user1, user2);
//map: {1=User(id=2, name=李四)}, user1: User(id=2, name=李四), user2: null
User user3 = hashMap.computeIfPresent(1, (k,oldValue) -> null);
log.info("map: {}, user3:{}", hashMap, user3);
//map: {}, user3:null
}
oldValue == null: 不覆蓋&返回nulloldValue != null && remappingFunction返回值 == null: 移除元素&返回nulloldValue != null && remappingFunction返回值 != null: 覆蓋元素&返回newValue
可以理解為 當key對應的value存在時, 才使用remappingFunction的返回值覆蓋對應key的舊值, 如果key對應的value不存在或者remappingFunction的返回值為null時, 則不覆蓋
源碼如下:
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);
if (newValue != null) {
put(key, newValue);
return newValue;
} else {
remove(key);
return null;
}
} else {
return null;
}
}
2.8 replace
// replace(K key, V value)
// replace(K key, V oldValue, V newValue) (替換)
@Test
public void replace() {
hashMap.put(1, zhangsan);
hashMap.put(2, lisi);
hashMap.replace(1, zhangtieniu);
hashMap.replace(2, null);
hashMap.replace(3, zhangtieniu);
hashMap.replace(2, null, zhangtieniu);
log.info("map: {}", hashMap);
//map: {1=User(id=3, name=張鐵牛), 2=User(id=3, name=張鐵牛)}
}
- 替換指定key的value值
- 可以將對應的value設置為null
- 對應的key不存在時不會添加新元素
replace(K key, V oldValue, V newValue)方法多了一層判斷, 當key對應的value與oldValue相等時, 才會替換newValue
可以理解為 替換指定key的value值
源碼如下:
default V replace(K key, V value) {
V curValue;
if (((curValue = get(key)) != null) || containsKey(key)) {
curValue = put(key, value);
}
return curValue;
}
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;
}
2.9 merge
// merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) (融合)
@Test
public void merge() {
hashMap.put(1, zhangsan);
User user1 = hashMap.merge(1, lisi, (oldValue, defaultValue) -> zhangtieniu);
User user2 = hashMap.merge(2, lisi, (oldValue, defaultValue) -> zhangtieniu);
log.info("map: {}, user1: {}, user2: {}", hashMap, user1, user2);
//map: {1=User(id=3, name=張鐵牛), 2=User(id=2, name=李四)}, user1: User(id=3, name=張鐵牛), user2: User(id=2, name=李四)
}
-
oldValue == null: 使用傳進來的 value 作為newValue,oldValue != null: 使用remappingFunction的返回值作為newValue-
newValue == null: 移除元素 & 返回newValue -
newValue != null: 覆蓋元素 & 返回newValue
-
可以理解為 融合三個值 分別為:
- key對應的value(oldValue)
- merge方法的第二個參數value (可以理解為oldValue的defaultValue)
- merge方法的第三個參數remappingFunction方法的返回值
融合邏輯為: 如果key對應的value不存在時, 使用merge方法的第二個參數value作為newValue, 如果key對應的value存在時,使用remappingFunction的返回值作為newValue, 如果newValue不為null則覆蓋元素, 為null則移除元素
源碼如下:
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);
if(newValue == null) {
remove(key);
} else {
put(key, newValue);
}
return newValue;
}
}
2.10 foreach
// foreach java8 新增
@Test
public void foreach() {
hashMap.put(1, zhangsan);
hashMap.put(2, lisi);
hashMap.forEach((key, value) -> log.info("key: {}, value: {}", key, value));
//key: 1, value: User(id=1, name=張三)
//key: 2, value: User(id=2, name=李四)
}
3. 總結
| 方法名稱 | 方法參數 | 方法描述 | 方法特點 |
|---|---|---|---|
| put | key, value | 添加元素 | hashmap/linkedhashmap: key, value 都可以為null |
| getOrDefault | key, defaultValue | 獲取元素 | 當map中沒有對應的key時, 返回defaultValue |
| putIfAbsent | key, value | 當不存在時添加元素 | 這里不存在指的是: key對應的舊值為null |
| compute | key, BiFunction<key, oldValue, newValue> remappingFunction | 重新計算key對應的value | 使用remappingFunction的返回值替換key的舊值 |
| computeIfAbsent | key, Function<key, value> mappingFunction | 當不存在時計算 | 這里不存在指的是: key對應的舊值為null, 與putIfAbsent方法邏輯類似 |
| computeIfPresent | key, BiFunction<key, oldValue, newValue> remappingFunction | 當存在時計算 | 這里存在指的是: key對應的舊值!=null |
| replace | key, value | 替換元素 | 替換指定key的value, 不會添加元素 |
| merge | key, value, BiFunction<oldValue, value, newValue> remappingFunction | 融合 | 融合key的舊值, 默認值, remappingFunction的返回值作為新值 |
| foreach | BiConsumer<key, value> | 遍歷 | java8新加的遍歷方式 |

浙公網安備 33010602011771號