Map之computeIfAbsent使用解讀
Map之computeIfAbsent
在Java編程中,Map
接口提供了一個(gè)便捷的方法computeIfAbsent
,它可以用來從map中獲取key對(duì)應(yīng)的value。如果value不存在,就使用提供的Function創(chuàng)建一個(gè)新的value,然后存入map中,最后返回這個(gè)新創(chuàng)建的value
computeIfAbsent方法是Java 8中引入的一種簡(jiǎn)化操作Map的方式。該方法通過自動(dòng)檢查鍵值對(duì)是否存在并生成缺失的值,減少了手動(dòng)檢查和插入的樣板代碼。它不僅使代碼更加簡(jiǎn)潔和易讀,還提高了操作的效率和一致性。
computeIfAbsent 方法的簡(jiǎn)介
computeIfAbsent
方法在Java 8中引入,用于簡(jiǎn)化在Map中獲取值的操作。
如果指定的鍵在Map中不存在,computeIfAbsent
會(huì)調(diào)用指定的函數(shù)來生成一個(gè)新的值,并將其與鍵關(guān)聯(lián)。
這樣,開發(fā)者不需要顯式地檢查鍵是否存在,從而減少了樣板代碼。
方法簽名
default V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction)
參數(shù)說明
key
:要在map中查找的鍵。mappingFunction
:用于生成默認(rèn)值的函數(shù)。
返回值
- 如果
key
已經(jīng)存在于map中,則返回對(duì)應(yīng)的value。 - 如果
key
不存在于map中,則使用mappingFunction
生成一個(gè)新value,存入map,并返回這個(gè)新value。
示例
優(yōu)化前的代碼
在沒有使用computeIfAbsent
方法之前,我們通常會(huì)這樣寫:
Map<String, Set<Pet>> statistics = new HashMap<>(); Set<Pet> pets = statistics.get(threadName); if (pets == null) { pets = new HashSet<>(); statistics.put(threadName, pets); }
優(yōu)化后的代碼
使用computeIfAbsent
方法后,代碼變得更加簡(jiǎn)潔和易讀:
Map<String, Set<Pet>> statistics = new HashMap<>(); Set<Pet> pets = statistics.computeIfAbsent(threadName, k -> new HashSet<>());
工作原理
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; }
詳細(xì)解釋
- 檢查現(xiàn)有值:首先檢查指定的鍵是否已經(jīng)存在于map中。
- 生成新值:如果鍵不存在,使用
mappingFunction
生成一個(gè)新的值。 - 存儲(chǔ)新值:將新生成的值與鍵關(guān)聯(lián)并存儲(chǔ)在map中。
- 返回值:返回與鍵關(guān)聯(lián)的值(新生成的或已存在的)。
實(shí)際應(yīng)用中的示例
示例1:統(tǒng)計(jì)單詞出現(xiàn)的次數(shù)
我們有一個(gè)文本,想統(tǒng)計(jì)每個(gè)單詞出現(xiàn)的次數(shù)。我們可以使用computeIfAbsent
方法來簡(jiǎn)化統(tǒng)計(jì)邏輯:
import java.util.*; public class WordCounter { public static void main(String[] args) { String text = "hello world hello Java hello world"; String[] words = text.split(" "); Map<String, Integer> wordCount = new HashMap<>(); for (String word : words) { wordCount.computeIfAbsent(word, k -> 0); wordCount.put(word, wordCount.get(word) + 1); } wordCount.forEach((k, v) -> System.out.println(k + ": " + v)); } }
在這個(gè)例子中,computeIfAbsent
方法確保每個(gè)單詞在第一次出現(xiàn)時(shí)被初始化為0,然后我們簡(jiǎn)單地增加計(jì)數(shù)值。
示例2:分組學(xué)生名單
假設(shè)我們有一組學(xué)生的成績(jī)記錄,我們想按分?jǐn)?shù)段對(duì)學(xué)生進(jìn)行分組。例如,分?jǐn)?shù)在90以上的分為一組,80-89分為一組,依此類推。
我們可以使用computeIfAbsent
方法來實(shí)現(xiàn)這個(gè)功能:
import java.util.*; public class StudentGrouper { public static void main(String[] args) { List<Student> students = Arrays.asList( new Student("Alice", 85), new Student("Bob", 92), new Student("Charlie", 87), new Student("David", 72), new Student("Eve", 90) ); Map<String, List<String>> gradeGroups = new HashMap<>(); for (Student student : students) { String gradeCategory = getGradeCategory(student.getScore()); gradeGroups.computeIfAbsent(gradeCategory, k -> new ArrayList<>()).add(student.getName()); } gradeGroups.forEach((k, v) -> System.out.println(k + ": " + v)); } public static String getGradeCategory(int score) { if (score >= 90) { return "90-100"; } else if (score >= 80) { return "80-89"; } else if (score >= 70) { return "70-79"; } else { return "Below 70"; } } } class Student { private String name; private int score; public Student(String name, int score) { this.name = name; this.score = score; } public String getName() { return name; } public int getScore() { return score; } }
在這個(gè)示例中,computeIfAbsent
方法確保每個(gè)分?jǐn)?shù)段(例如“90-100”)被正確初始化為一個(gè)新的ArrayList
,然后我們將學(xué)生的名字添加到對(duì)應(yīng)的分組中。
示例3:構(gòu)建依賴圖
假設(shè)我們有一組任務(wù),每個(gè)任務(wù)可能依賴于其他任務(wù)。我們希望構(gòu)建一個(gè)依賴圖,表示每個(gè)任務(wù)的依賴關(guān)系。我們可以使用computeIfAbsent
方法來簡(jiǎn)化圖的構(gòu)建:
import java.util.*; public class DependencyGraph { public static void main(String[] args) { Map<String, List<String>> dependencies = new HashMap<>(); addDependency(dependencies, "Task1", "Task2"); addDependency(dependencies, "Task1", "Task3"); addDependency(dependencies, "Task2", "Task4"); addDependency(dependencies, "Task3", "Task4"); addDependency(dependencies, "Task4", "Task5"); dependencies.forEach((k, v) -> System.out.println(k + " depends on " + v)); } public static void addDependency(Map<String, List<String>> dependencies, String task, String dependency) { dependencies.computeIfAbsent(task, k -> new ArrayList<>()).add(dependency); } }
在這個(gè)示例中,computeIfAbsent
方法確保每個(gè)任務(wù)都有一個(gè)對(duì)應(yīng)的依賴列表。如果任務(wù)不存在,則初始化一個(gè)新的ArrayList
并添加依賴關(guān)系。
示例4:緩存計(jì)算結(jié)果
在某些場(chǎng)景中,計(jì)算某些值可能非常耗時(shí),因此我們希望緩存計(jì)算結(jié)果以提高效率。我們可以使用computeIfAbsent
方法來實(shí)現(xiàn)簡(jiǎn)單的緩存:
import java.util.*; public class FibonacciCache { private static Map<Integer, Integer> cache = new HashMap<>(); public static void main(String[] args) { System.out.println(fibonacci(10)); // 輸出:55 System.out.println(fibonacci(20)); // 輸出:6765 System.out.println(fibonacci(30)); // 輸出:832040 } public static int fibonacci(int n) { if (n <= 1) { return n; } return cache.computeIfAbsent(n, k -> fibonacci(k - 1) + fibonacci(k - 2)); } }
在這個(gè)示例中,computeIfAbsent
方法用于緩存斐波那契數(shù)列的計(jì)算結(jié)果。對(duì)于每一個(gè)n,如果緩存中不存在對(duì)應(yīng)的值,則進(jìn)行計(jì)算并緩存結(jié)果。這種方法大大提高了計(jì)算效率,避免了重復(fù)計(jì)算。
優(yōu)勢(shì)總結(jié)
使用computeIfAbsent
方法有以下幾個(gè)優(yōu)勢(shì):
- 簡(jiǎn)潔性:減少了樣板代碼,使代碼更加簡(jiǎn)潔和易讀。
- 避免重復(fù)代碼:通過使用
computeIfAbsent
方法,我們避免了顯式的空檢查和插入邏輯。 - 線程安全性:對(duì)于某些并發(fā)Map實(shí)現(xiàn)(如
ConcurrentHashMap
),computeIfAbsent
提供了線程安全的方式來處理映射關(guān)系。 - 性能提升:在需要緩存計(jì)算結(jié)果或避免重復(fù)計(jì)算的場(chǎng)景中,
computeIfAbsent
可以顯著提高性能。 - 代碼一致性:通過使用
computeIfAbsent
,代碼更加一致和規(guī)范,易于維護(hù)。
通過理解和使用computeIfAbsent
方法,開發(fā)者可以寫出更簡(jiǎn)潔、易讀且高效的代碼,使得在操作map時(shí)更加得心應(yīng)手。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
詳解java并發(fā)之重入鎖-ReentrantLock
這篇文章主要介紹了java并發(fā)之重入鎖-ReentrantLock,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-03-03最優(yōu)雅地整合 Spring & Spring MVC & MyBatis 搭建 Java 企業(yè)級(jí)應(yīng)用(附源碼)
這篇文章主要介紹了最優(yōu)雅地整合 Spring & Spring MVC & MyBatis 搭建 Java 企業(yè)級(jí)應(yīng)用(附源碼),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-01-01詳解springboot?springsecuroty中的注銷和權(quán)限控制問題
這篇文章主要介紹了springboot-springsecuroty?注銷和權(quán)限控制,賬戶注銷需要在SecurityConfig中加入開啟注銷功能的代碼,權(quán)限控制要導(dǎo)入springsecurity和thymeleaf的整合依賴,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友參考下吧2022-03-03Springboot初始化啟動(dòng)報(bào)錯(cuò)Error?creating?bean?with?name?'da
這篇文章主要為大家介紹了Springboot初始化啟動(dòng)報(bào)Error?creating?bean?with?name?'dataSource'?defined?in?class?path?resource解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-08-08spring?和?idea?建議不要使用?@Autowired注解的原因解析
@Autowired?是Spring框架的注解,而@Resource是JavaEE的注解,這篇文章主要介紹了spring和idea建議不要使用@Autowired注解的相關(guān)知識(shí),需要的朋友可以參考下2023-11-11spring中@Autowired自動(dòng)注入依賴項(xiàng)的使用
當(dāng)使用@Autowired注解時(shí),它可以自動(dòng)注入依賴項(xiàng),例如其他類的實(shí)例,本文就來詳細(xì)的介紹一下,具有一定的參考價(jià)值,感興趣的可以了解一下2023-09-09java反射校驗(yàn)參數(shù)是否是基礎(chǔ)類型步驟示例
這篇文章主要為大家介紹了java反射校驗(yàn)參數(shù)是否是基礎(chǔ)類型步驟示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-12-12java使用http實(shí)現(xiàn)文件下載學(xué)習(xí)示例
這篇文章主要介紹了java使用http實(shí)現(xiàn)文件下載學(xué)習(xí)示例,需要的朋友可以參考下2014-04-04