Map之computeIfAbsent使用解讀
Map之computeIfAbsent
在Java編程中,Map接口提供了一個(gè)便捷的方法computeIfAbsent,它可以用來(lái)從map中獲取key對(duì)應(yīng)的value。如果value不存在,就使用提供的Function創(chuàng)建一個(gè)新的value,然后存入map中,最后返回這個(gè)新創(chuàng)建的value
computeIfAbsent方法是Java 8中引入的一種簡(jiǎn)化操作Map的方式。該方法通過(guò)自動(dòng)檢查鍵值對(duì)是否存在并生成缺失的值,減少了手動(dòng)檢查和插入的樣板代碼。它不僅使代碼更加簡(jiǎn)潔和易讀,還提高了操作的效率和一致性。
computeIfAbsent 方法的簡(jiǎn)介
computeIfAbsent方法在Java 8中引入,用于簡(jiǎn)化在Map中獲取值的操作。
如果指定的鍵在Map中不存在,computeIfAbsent會(huì)調(diào)用指定的函數(shù)來(lái)生成一個(gè)新的值,并將其與鍵關(guān)聯(lián)。
這樣,開(kāi)發(fā)者不需要顯式地檢查鍵是否存在,從而減少了樣板代碼。
方法簽名
default V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction)
參數(shù)說(shuō)明
key:要在map中查找的鍵。mappingFunction:用于生成默認(rèn)值的函數(shù)。
返回值
- 如果
key已經(jīng)存在于map中,則返回對(duì)應(yīng)的value。 - 如果
key不存在于map中,則使用mappingFunction生成一個(gè)新value,存入map,并返回這個(gè)新value。
示例
優(yōu)化前的代碼
在沒(méi)有使用computeIfAbsent方法之前,我們通常會(huì)這樣寫(xiě):
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方法來(lái)簡(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方法來(lái)實(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方法來(lái)簡(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方法來(lái)實(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ù)代碼:通過(guò)使用
computeIfAbsent方法,我們避免了顯式的空檢查和插入邏輯。 - 線程安全性:對(duì)于某些并發(fā)Map實(shí)現(xiàn)(如
ConcurrentHashMap),computeIfAbsent提供了線程安全的方式來(lái)處理映射關(guān)系。 - 性能提升:在需要緩存計(jì)算結(jié)果或避免重復(fù)計(jì)算的場(chǎng)景中,
computeIfAbsent可以顯著提高性能。 - 代碼一致性:通過(guò)使用
computeIfAbsent,代碼更加一致和規(guī)范,易于維護(hù)。
通過(guò)理解和使用computeIfAbsent方法,開(kāi)發(fā)者可以寫(xiě)出更簡(jiǎn)潔、易讀且高效的代碼,使得在操作map時(shí)更加得心應(yīng)手。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
詳解java并發(fā)之重入鎖-ReentrantLock
這篇文章主要介紹了java并發(fā)之重入鎖-ReentrantLock,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(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)限控制問(wèn)題
這篇文章主要介紹了springboot-springsecuroty?注銷和權(quán)限控制,賬戶注銷需要在SecurityConfig中加入開(kāi)啟注銷功能的代碼,權(quán)限控制要導(dǎo)入springsecurity和thymeleaf的整合依賴,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友參考下吧2022-03-03
Springboot初始化啟動(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-08
spring?和?idea?建議不要使用?@Autowired注解的原因解析
@Autowired?是Spring框架的注解,而@Resource是JavaEE的注解,這篇文章主要介紹了spring和idea建議不要使用@Autowired注解的相關(guān)知識(shí),需要的朋友可以參考下2023-11-11
spring中@Autowired自動(dòng)注入依賴項(xiàng)的使用
當(dāng)使用@Autowired注解時(shí),它可以自動(dòng)注入依賴項(xiàng),例如其他類的實(shí)例,本文就來(lái)詳細(xì)的介紹一下,具有一定的參考價(jià)值,感興趣的可以了解一下2023-09-09
java反射校驗(yàn)參數(shù)是否是基礎(chǔ)類型步驟示例
這篇文章主要為大家介紹了java反射校驗(yàn)參數(shù)是否是基礎(chǔ)類型步驟示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-12-12
java使用http實(shí)現(xiàn)文件下載學(xué)習(xí)示例
這篇文章主要介紹了java使用http實(shí)現(xiàn)文件下載學(xué)習(xí)示例,需要的朋友可以參考下2014-04-04

