在Java 8中,Map介面新增了一個非常實用的方法,即computeIfAbsent()方法。該方法的作用相當於「如果key對應的value不存在,則計算相應的value並put到map中」,是applyIfAbsent()方法的變體。在本文中,我們將從多個方面對該方法做詳細的闡述。
一、基本用法
public V computeIfAbsent(K key, Function mappingFunction)
該方法的參數包含key和一個mappingFunction,mappingFunction是一個根據key計算相應value的函數。
下面是一個基本的示例代碼:
Map<String, Integer> map = new HashMap<>();
map.put("apple", 1);
map.put("banana", null);
map.computeIfAbsent("apple", k -> k.length()); // 值存在,不計算
map.computeIfAbsent("banana", k -> k.length()); // 值為null,計算值得長度3
map.computeIfAbsent("pear", k -> k.length()); // 值不存在,計算值得長度4
System.out.println(map); // 輸出:{banana=3, pear=4, apple=1}
從上面的代碼可以看出,apple已經存在,因此不計算value的值,而banana的value為null,需要根據其key計算value的長度為3。最後,由於pear的value不存在,需要根據其key計算value的長度為4。
二、踩坑實例
儘管computeIfAbsent()看起來非常簡單易用,但是在使用的時候,我們也需要注意某些細節,否則可能會出現意想不到的結果。
1. 注意函數的空指針
Map<String, String> map = new HashMap<>();
map.put("apple", "red");
map.computeIfAbsent("banana", String::toUpperCase); // 函數無空指針問題
map.computeIfAbsent("orange", String::toUpperCase); // 函數中空指針,拋出NullPointerException異常
System.out.println(map);
在上面的代碼中,我們傳遞了一個方法引用String::toUpperCase作為映射函數,但是當key為orange時,該方法會拋出一個NullPointerException異常。為了避免這個問題,可以把映射函數包裝在一個方法中。
public String uppercase(String s) {
return s != null ? s.toUpperCase() : null;
}
Map<String, String> map = new HashMap<>();
map.put("apple", "red");
map.computeIfAbsent("banana", this::uppercase); // 函數無空指針問題
map.computeIfAbsent("orange", this::uppercase); // 函數中空指針,返回null
System.out.println(map);
2. 注意函數的可重複使用性
Map<String, String> map = new HashMap<>();
String[] arr = new String[] { "apple", "banana" };
for (String s : arr) {
map.computeIfAbsent(s, String::toUpperCase);
}
System.out.println(map); // 輸出:{banana=BANANA, apple=APPLE}
在上面的代碼中,我們在for循環中多次調用了String::toUpperCase方法,每次都new了一個新的Function實例。這不僅效率低下,而且也不符合computeIfAbsent()方法的設計初衷。為了優化這個問題,我們可以將方法引用封裝在一個靜態屬性或者方法中。
public static final Function<String, String> TO_UPPER_CASE = String::toUpperCase;
Map<String, String> map = new HashMap<>();
String[] arr = new String[] { "apple", "banana" };
for (String s : arr) {
map.computeIfAbsent(s, TO_UPPER_CASE);
}
System.out.println(map); // 輸出:{banana=BANANA, apple=APPLE}
三、高級用法
1. 引用兩個參數
如果映射函數需要用到Map的另一個參數,那麼我們可以使用Lambda表達式引用它:
Map<String, Integer> map = new HashMap<>();
map.put("apple", 1);
map.put("banana", null);
map.computeIfAbsent("banana", k -> k != null ? k.length() : 0);
map.computeIfAbsent("pear", k -> map.size() + k.length());
System.out.println(map); // 輸出:{pear=8, banana=0, apple=1}
2. 使用Supplier作為參數
使用Supplier的好處在於僅當需要計算值時才會觸發計算,這可以避免不必要的計算開銷。下面是一個示例代碼:
Map<String, String> map = new HashMap<>();
map.put("apple", "sweet");
map.computeIfAbsent("banana", () -> "sour");
map.computeIfAbsent("orange", () -> {
System.out.println("computing...");
return "fresh";
});
System.out.println(map); // 輸出:{orange=fresh, banana=sour, apple=sweet}
從上面的代碼可以看出,當key為banana時,我們並不需要計算value的值,而當key為orange時,此時才需要真正計算value的值,而不是在初始化時進行計算。此外,由於Supplier的返回值可以為null,這種方式也可以用來避免空指針異常。
3. 講解compute()方法
與computeIfAbsent()方法類似,compute()方法也是Map介面新增的一個方法。它的作用是「如果key存在,則更新key對應的value,否則put一個新的key-value映射到Map中」。
下面是一個示例代碼:
Map<String, Integer> map = new HashMap<>();
map.put("apple", 1);
map.compute("banana", (k, v) -> v == null ? 0 : v + 1);
map.compute("apple", (k, v) -> v == null ? 0 : v + 1);
System.out.println(map); // 輸出:{banana=0, apple=2}
從上面的代碼可以看出,當key為banana時,value不存在,因此put了一個新的key-value映射到Map中。而當key為apple時,對應的value為1,根據計算邏輯,更新後的value為2。
4. 實用的計數器
下面是使用compute()方法實現一個簡單計數器的實例:
Map<String, Integer> map = new HashMap<>();
String[] arr = new String[] { "apple", "banana", "banana", "pear", "pear", "pear" };
for (String s : arr) {
map.compute(s, (k, v) -> v == null ? 1 : v + 1);
}
System.out.println(map); // 輸出:{banana=2, pear=3, apple=1}
從上面的代碼可以看出,我們根據數組arr遍歷key,如果key已經存在,則更新其對應的value,否則put一個新的key-value映射到Map中。最終,我們得到了一個計數器map,其中key為數組arr中的元素,value為該元素在數組中出現的次數。
四、總結
本文介紹了Java 8中Map介面新增的一個非常實用的方法computeIfAbsent()。該方法和compute()方法一樣,都能夠在Map不存在指定key的情況下進行計算並put到Map中。同時,我們還通過一些示例代碼,探討了該方法的高級用法以及踩坑注意事項。希望本文能夠幫助大家更好地理解和使用computeIfAbsent()方法。
原創文章,作者:RIQK,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/144011.html