詳解map.computeIfAbsent方法

在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

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
RIQK的頭像RIQK
上一篇 2024-10-24 15:26
下一篇 2024-10-24 15:26

相關推薦

  • 解決.net 6.0運行閃退的方法

    如果你正在使用.net 6.0開發應用程序,可能會遇到程序閃退的情況。這篇文章將從多個方面為你解決這個問題。 一、代碼問題 代碼問題是導致.net 6.0程序閃退的主要原因之一。首…

    編程 2025-04-29
  • ArcGIS更改標註位置為中心的方法

    本篇文章將從多個方面詳細闡述如何在ArcGIS中更改標註位置為中心。讓我們一步步來看。 一、禁止標註智能調整 在ArcMap中設置標註智能調整可以自動將標註位置調整到最佳顯示位置。…

    編程 2025-04-29
  • Python中init方法的作用及使用方法

    Python中的init方法是一個類的構造函數,在創建對象時被調用。在本篇文章中,我們將從多個方面詳細討論init方法的作用,使用方法以及注意點。 一、定義init方法 在Pyth…

    編程 2025-04-29
  • Python創建分配內存的方法

    在python中,我們常常需要創建並分配內存來存儲數據。不同的類型和數據結構可能需要不同的方法來分配內存。本文將從多個方面介紹Python創建分配內存的方法,包括列表、元組、字典、…

    編程 2025-04-29
  • 用不同的方法求素數

    素數是指只能被1和自身整除的正整數,如2、3、5、7、11、13等。素數在密碼學、計算機科學、數學、物理等領域都有著廣泛的應用。本文將介紹幾種常見的求素數的方法,包括暴力枚舉法、埃…

    編程 2025-04-29
  • Python中讀入csv文件數據的方法用法介紹

    csv是一種常見的數據格式,通常用於存儲小型數據集。Python作為一種廣泛流行的編程語言,內置了許多操作csv文件的庫。本文將從多個方面詳細介紹Python讀入csv文件的方法。…

    編程 2025-04-29
  • 使用Vue實現前端AES加密並輸出為十六進位的方法

    在前端開發中,數據傳輸的安全性問題十分重要,其中一種保護數據安全的方式是加密。本文將會介紹如何使用Vue框架實現前端AES加密並將加密結果輸出為十六進位。 一、AES加密介紹 AE…

    編程 2025-04-29
  • Python學習筆記:去除字元串最後一個字元的方法

    本文將從多個方面詳細闡述如何通過Python去除字元串最後一個字元,包括使用切片、pop()、刪除、替換等方法來實現。 一、字元串切片 在Python中,可以通過字元串切片的方式來…

    編程 2025-04-29
  • 用法介紹Python集合update方法

    Python集合(set)update()方法是Python的一種集合操作方法,用於將多個集合合併為一個集合。本篇文章將從以下幾個方面進行詳細闡述: 一、參數的含義和用法 Pyth…

    編程 2025-04-29
  • Vb運行程序的三種方法

    VB是一種非常實用的編程工具,它可以被用於開發各種不同的應用程序,從簡單的計算器到更複雜的商業軟體。在VB中,有許多不同的方法可以運行程序,包括編譯器、發布程序以及命令行。在本文中…

    編程 2025-04-29

發表回復

登錄後才能評論