Java8 新特性連載——Map的騷操作

細心的童鞋不知道有沒有發現,Java8中的Map容器是沒有流式操作的,不過可以通過keySet和values方法獲得鍵或值列表來間接使用stream,但是,翻看Map的源碼時可以發現,除了關於容器本身的操作虛方法以外,多出來很多默認方法,這些方法對於我們操作Map真是太有用了,我把常用的挑出來一一說明:

1、getOrDefault

default V getOrDefault(Object key, V defaultValue) {
V v;
return (((v = get(key)) != null) || containsKey(key))
? v
: defaultValue;
}

這個很好理解,我們獲取Map中元素時可以方便的給一個默認值,舉個例子:我們要統計一個容器中相同數字的個數:

沒有這個騷操作的時候的可能寫法:

List<integer> numbers;
Map<integer> numberCount;
for(Integer number : numbers) {
Integer count = numberCount.get(number);
if(count == null) {
count = 1;
} else {
count++;
}
numberCount.put(number, count);
}
/<integer>/<integer>

有這個方法後我們可以這麼寫:

List<integer> numbers;
Map<integer> numberCount;
for(Integer number : numbers) {
int count = numberCount.getOrDefault(number, 0) + 1;
numberCount.put(number, count);
}
/<integer>/<integer>

2、forEach

Map的遍歷不管是官方還是民間大佬都是如此:

Map<integer> map = new HashMap<>();
for (Map.Entry<integer> entry : map.entrySet()) {
Integer key = entry.getKey();
Integer value = entry.getValue();
System.out.println(key + "-" + value);
}
/<integer>/<integer>

其實也還可以吧,代碼略顯臃腫而已,現在我們又多一個選擇:

Map<integer> map = new HashMap<>();
map.forEach((k, v) -> System.out.println(k +"-" + v));
/<integer>

3、replaceAll

這也是批量修改神器:假如有個以User的ID為Key,User為Value的Map,而User的暱稱有的為空,我們需要把暱稱為空的統一用ID填充,我們通常這麼寫:

Map<string> map = new HashMap<>();
for (Map.Entry<string> entry : map.entrySet()) {
String key = entry.getKey();
User value = entry.getValue();
if(value.getNickName() == null) {
value.setNickName(key);
}
}
/<string>/<string>

神器來了!

Map<string> map = new HashMap<>();
map.replaceAll((k, v) -> v.setNickName(Optional.ofNullable(v.getNickName()).orElse(k)));
/<string>

4、putIfAbsent

就是如果當前Key在Map中不存在就put。

// 老方法
Map<string> map = new HashMap<>();
User tom = map.get("tom");
if(tom == null) {
map.put("tom", new User("tom");
}

// 騷操作
map.putIfAbsent("tom", new User("tom"));
/<string>

5、remove

default boolean remove(Object key, Object value)

這個remove與原先的remove不一樣,它刪除的條件是指定Key的Value必須與提供的value相同,等同於以下代碼實現:

if (map.containsKey(key) && Objects.equals(map.get(key), value)) {
map.remove(key);
return true;
} else
return false;
}

說實話這個騷操作使用場景感覺不會很常遇到,相當於對於remove(Key)多了一層校驗?

6、replace

default V replace(K key, V value) 

這個操作與普通的put最大的區別就在於一般我們直接put時是不管map中是否已經存在該key,都會進行覆蓋;而replace則是隻有map中存在這個key時才覆蓋。

7、computeIfAbsent

該操作首先判斷提供的Key在map中是否存在,如果不存在,則根據輸入的Key進行處理生成一個值,然後put到Map中

Map<integer> sqrt = new HashMap<>();
sqrt.computeIfAbsent(34, Math::sqrt);
/<integer>

8、computeIfPresent

與操作7不同,該操作前提Map中存在key,且該Key映射的對象不能為空,然後該操作會根據提供的算子將舊Key和舊值進行計算後得到新值,若新值不為null則替換,若為空則刪除該Key

Map<integer> sqrt = new HashMap<>();
sqrt.computeIfPresent(34, (k, v) -> null); // 此時Key=34的元素將被刪除
sqrt.put(3, 7);
sqrt.computeIfPresent(3, (k, v) -> k * v);// 此時key=3的元素值為21
/<integer>

9、compute

相當於是與操作7和8的結合體,如果給定Key值存在執行操作8,否則執行操作7

10、merge

合併操作,如果key值不存在,則直接用新值替換;否則根據提供的算子處理新值與舊值,如果處理結果為空刪除key,否則用處理結果替換value。

Map<integer> map = new HashMap<>();
map.put(23, "Tom");
map.merge(24, "Kitty", (o, n) -> o + "==" + n);// Key=24的值為Kitty
map.merge(23, "Cat", (o, n) -> o + "&&" + n);// Key=23的值為Tom&&Cat
/<integer>

騷不騷?


分享到:


相關文章: