java高效累加map中相同key對(duì)應(yīng)的Value值
在Java中,對(duì)于??Map??中的相同鍵(key)進(jìn)行值(value)累加的操作是常見(jiàn)的需求之一。這種操作可以通過(guò)多種方式實(shí)現(xiàn),具體取決于你使用的Java版本以及你希望達(dá)到的效果。下面將詳細(xì)介紹幾種不同的方法來(lái)完成這一任務(wù),并引用相關(guān)資料中的信息。
使用??merge??方法(推薦)
從Java 8開(kāi)始,??Map???接口引入了??merge??方法,它提供了一種便捷的方式來(lái)在鍵已經(jīng)存在的情況下合并值。此方法接收三個(gè)參數(shù):鍵、新值和一個(gè)用于處理沖突的函數(shù)。當(dāng)給定的鍵不存在時(shí),該方法會(huì)簡(jiǎn)單地將鍵與提供的新值關(guān)聯(lián)起來(lái);如果鍵已經(jīng)存在,則調(diào)用提供的函數(shù)來(lái)計(jì)算新的值。例如:
Map<String, Integer> map = new HashMap<>();
map.merge("key1", 1, Integer::sum);
map.merge("key1", 2, Integer::sum); // 如果 "key1" 存在,則將其值更新為原值加上2
System.out.println(map); // 輸出: {key1=3}
這種方法不僅簡(jiǎn)潔明了,而且避免了顯式檢查鍵是否存在或手動(dòng)獲取舊值再進(jìn)行累加的操作。
使用??compute??方法
除了??merge???之外,??compute??也是一個(gè)非常有用的工具。它可以接受一個(gè)鍵和一個(gè)雙參數(shù)函數(shù)作為輸入,其中第一個(gè)參數(shù)是鍵本身,第二個(gè)參數(shù)是當(dāng)前映射到該鍵的值(如果沒(méi)有則為null)。根據(jù)這個(gè)函數(shù)返回的結(jié)果決定是否更新或插入新的鍵值對(duì)。對(duì)于累加的情況,你可以這樣寫(xiě):
map.compute("key1", (k, v) -> v == null ? 1 : v + 1);
這段代碼實(shí)現(xiàn)了與上面??merge???示例相同的功能,但是通過(guò)??compute??提供了更多的靈活性,因?yàn)樗试S你在更復(fù)雜的情況下自定義如何處理鍵值對(duì)。
遍歷并累加
如果你有一個(gè)包含多個(gè)條目的集合,并且想要基于某些條件對(duì)這些條目進(jìn)行分組并累加它們的值,那么可以考慮使用流(Stream API)。例如,假設(shè)我們有一個(gè)??List<Map<String, Integer>>???,其中每個(gè)??Map??代表一行記錄,我們可以按照特定的鍵來(lái)聚合數(shù)據(jù):
List<Map<String, Integer>> list = Arrays.asList(
Map.of("id", 1, "amount", 10),
Map.of("id", 2, "amount", 20),
Map.of("id", 1, "amount", 30)
);
Map<Integer, Integer> result = list.stream()
.flatMap(m -> m.entrySet().stream())
.filter(e -> "id".equals(e.getKey()) || "amount".equals(e.getKey()))
.collect(Collectors.groupingBy(
e -> Integer.parseInt(e.getValue().toString()),
Collectors.summingInt(e -> "amount".equals(e.getKey()) ? e.getValue() : 0)
));
System.out.println(result); // 輸出: {1=40, 2=20}
這里我們首先將所有的??Map.Entry???展平成一個(gè)流,然后過(guò)濾出感興趣的字段(即??id???和??amount???),最后使用??Collectors.groupingBy???結(jié)合??Collectors.summingInt??來(lái)進(jìn)行分組和累加。
處理復(fù)雜類(lèi)型
當(dāng)??Map???中的值不是簡(jiǎn)單的數(shù)字而是更復(fù)雜的對(duì)象時(shí),可能需要采取稍微不同的策略。例如,如果你有一個(gè)??Map<String, BigDecimal>??并且想對(duì)相同的鍵進(jìn)行累加,可以這樣做:
Map<String, BigDecimal> decimalMap = new HashMap<>();
list.forEach(data -> {
String id = data.get("id").toString();
BigDecimal amount = new BigDecimal(data.get("amount").toString());
BigDecimal currentValue = decimalMap.get(id);
if (currentValue != null) {
decimalMap.put(id, currentValue.add(amount));
} else {
decimalMap.put(id, amount);
}
});
這段代碼展示了如何遍歷一個(gè)列表并將每個(gè)元素的金額累加到相應(yīng)的鍵下。注意這里使用了??BigDecimal??來(lái)進(jìn)行精確的小數(shù)運(yùn)算,這對(duì)于財(cái)務(wù)相關(guān)的應(yīng)用尤為重要。
方法補(bǔ)充
傳統(tǒng)遍歷累加方式
最直接的思路是遍歷 Map。示例代碼如下:
import java.util.HashMap;
import java.util.Map;
public class MapKeyAccumulate {
public static void main(String[] args) {
Map<String, Integer> productSales = new HashMap<>();
productSales.put("Apple", 10);
productSales.put("Banana", 5);
productSales.put("Apple", productSales.get("Apple") + 15);
for (Map.Entry<String, Integer> entry : productSales.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
}
}這段代碼手動(dòng)處理了 Apple 鍵的累加,先獲取舊值再加新值更新回去。但如果數(shù)據(jù)量龐大、重復(fù)鍵眾多,這種逐一手動(dòng)處理的方式極易出錯(cuò)且效率低下,代碼也顯得冗長(zhǎng)繁瑣。
利用 merge 方法(Java 8 及以上)
Java 8 引入的 merge 方法為這類(lèi)問(wèn)題提供了優(yōu)雅高效的解法。它能在鍵存在時(shí)合并值,鍵不存在時(shí)直接插入新鍵值對(duì)。示例如下:
import java.util.HashMap;
import java.util.Map;
public class MapMergeExample {
public static void main(String[] args) {
Map<String, Integer> productSales = new HashMap<>();
productSales.put("Apple", 10);
productSales.put("Banana", 5);
// 新數(shù)據(jù)
Map<String, Integer> newData = new HashMap<>();
newData.put("Apple", 15);
newData.put("Orange", 8);
for (Map.Entry<String, Integer> entry : newData.entrySet()) {
productSales.merge(entry.getKey(), entry.getValue(), Integer::sum);
}
productSales.forEach((key, value) -> System.out.println(key + ": " + value));
}
}在上述代碼中,merge 方法接收三個(gè)參數(shù):鍵、新值以及合并函數(shù)(這里用 Integer::sum 表示對(duì)兩個(gè)整數(shù)值求和)。當(dāng) productSales 中存在 merge 方法傳入的鍵時(shí),就將該鍵對(duì)應(yīng)的值與新值按給定函數(shù)合并;若鍵不存在,就把新鍵值對(duì)插入 productSales。這樣無(wú)需復(fù)雜的條件判斷,一行代碼搞定累加邏輯,簡(jiǎn)潔高效,尤其適用于動(dòng)態(tài)添加數(shù)據(jù)并實(shí)時(shí)合并的場(chǎng)景。
使用 computeIfPresent 方法
computeIfPresent 方法也可用于處理相同鍵累加,它針對(duì)已存在的鍵執(zhí)行計(jì)算操作。示例:
import java.util.HashMap;
import java.util.Map;
public class MapComputeExample {
public static void main(String[] args) {
Map<String, Integer> productSales = new HashMap<>();
productSales.put("Apple", 10);
productSales.put("Banana", 5);
Map<String, Integer> newData = new HashMap<>();
newData.put("Apple", 15);
newData.put("Orange", 8);
newData.forEach((key, newValue) -> productSales.computeIfPresent(key, (k, oldValue) -> oldValue + newValue));
productSales.putAll(newData);
productSales.forEach((key, value) -> System.out.println(key + ": " + value));
}
}這里遍歷 newData,對(duì)于 productSales 中已有的鍵,通過(guò) computeIfPresent 取出舊值與新值相加更新;遍歷結(jié)束后再用 putAll 插入新鍵值對(duì)(處理 newData 中不存在于 productSales 的鍵)。此方法靈活性高,可自定義復(fù)雜計(jì)算邏輯,不僅限于求和,如根據(jù)業(yè)務(wù)規(guī)則加權(quán)計(jì)算等。
總結(jié)
綜上所述,Java提供了多種方式來(lái)處理??Map???中相同鍵的值累加問(wèn)題。對(duì)于現(xiàn)代Java開(kāi)發(fā)而言,推薦優(yōu)先考慮??merge???或??compute??這樣的內(nèi)置方法,因?yàn)樗鼈儾粌H簡(jiǎn)化了代碼邏輯,還提高了程序的可讀性和維護(hù)性。而在面對(duì)更加復(fù)雜的場(chǎng)景時(shí),則可以根據(jù)實(shí)際情況選擇最適合的方法。無(wú)論選擇哪種方法,都應(yīng)該確保你的解決方案能夠正確處理所有邊界情況,包括但不限于空值、不同類(lèi)型的值以及并發(fā)訪問(wèn)等問(wèn)題.
到此這篇關(guān)于java高效累加map中相同key對(duì)應(yīng)的Value值的文章就介紹到這了,更多相關(guān)java累加map相同key的Value值內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解Java利用同步塊synchronized()保證并發(fā)安全
這篇文章主要介紹了Java利用同步塊synchronized()保證并發(fā)安全,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-03-03
擴(kuò)展logback將日志輸出到Kafka實(shí)例詳解
logback是一個(gè)功能強(qiáng)大的Java日志框架,它是log4j的繼任者,提供了豐富的功能和配置選項(xiàng),本文將介紹如何通過(guò)擴(kuò)展logback,將日志輸出到Kafka實(shí)例,感興趣的朋友一起看看吧2024-12-12
帶你重新認(rèn)識(shí)MyBatis的foreach
這篇文章主要介紹了重新認(rèn)識(shí)MyBatis的foreach,本文提出了一種簡(jiǎn)化<foreach>寫(xiě)法的設(shè)想,更重要的是通過(guò)解決空集時(shí)生成的SQL語(yǔ)法問(wèn)題,更深刻地理解MyBatis的foreach的生成機(jī)制,需要的朋友可以參考下2022-11-11
通過(guò)實(shí)例了解Java jdk和jre的區(qū)別
這篇文章主要介紹了通過(guò)實(shí)例了解Java jdk和jre的區(qū)別,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-05-05
Java中json使用方法_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
JSON(JavaScript Object Notation) 是一種輕量級(jí)的數(shù)據(jù)交換格式, json是個(gè)非常重要的數(shù)據(jù)結(jié)構(gòu),在web開(kāi)發(fā)中應(yīng)用十分廣泛。下面通過(guò)本文給大家講解Java中json使用方法,感興趣的朋友一起看看吧2017-07-07
Spring Boot項(xiàng)目打包和運(yùn)行的操作方法
Spring Boot 應(yīng)用內(nèi)嵌了 Web 服務(wù)器,所以基于 Spring Boot 開(kāi)發(fā)的 web應(yīng)用也可以獨(dú)立運(yùn)行,無(wú)須部署到其他 Web服務(wù)器中,下面以打包demo_test1項(xiàng)目為例,將 Spring Boot 項(xiàng)目打包為可執(zhí)行的 JAR 包并運(yùn)行,感興趣的朋友一起看看吧2025-05-05

