將entrySet()的流收集到LinkedHashMap
1. 概述
在本教程中,我們將探索將Map.Entry
物件流收集到LinkedHashMap
中的不同方法。
LinkedHashMap與HashMap
類似**,但不同之處在於它維護插入順序。**
2. 理解問題
我們可以透過呼叫entrySet()
方法和stream()
方法來取得映射條目流。該流使我們能夠處理每個條目。
處理是透過中間操作實現的,可以涉及透過filter()
方法進行過濾或透過map()
方法進行轉換。最終,我們必須透過適當的終端操作來決定我們想要對流做什麼。在我們的例子中,我們面臨著將串流收集到LinkedHashMap
中的挑戰。
假設本教學有以下地圖:
Map<Integer, String> map = Map.of(1, "value 1", 2, "value 2");
我們將把映射條目串流並收集到LinkedHashMap
中,並旨在滿足以下斷言:
assertThat(result)
.isExactlyInstanceOf(LinkedHashMap.class)
.containsOnly(entry(1, "value 1"), entry(2, "value 2"));
3.使用Collectors.toMap()
方法
我們可以使用Collectors.toMap()
方法的重載將流收集到我們選擇的映射中:
static <T, K, U, M extends Map<K, U>>
Collector<T, ?, M> toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper,
BinaryOperator<U> mergeFunction, Supplier<M> mapFactory)
因此,我們使用此收集器作為流的終端collect()
操作的一部分:
map
.entrySet()
.stream()
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> {throw new RuntimeException();}, LinkedHashMap::new));
為了保留每個條目的鍵值對,我們對keyMapper
和valueMapper
函數使用方法來引用Map.Entry::getKey
和Map.Entry::getValue
。 mergeFunction
允許我們處理具有相同鍵的條目的任何衝突。因此,我們拋出RuntimeException
,因為我們的用例不應該有任何衝突。最後,我們使用mapFactory 的LinkedHashMap
mapFactory
函數引用來提供將收集條目的對應。
我們應該注意到,可以使用其他toMap()
重載來實現我們的目標。但是,這些方法缺少mapFactory
參數,因此流被收集到底層的HashMap
中。因此,我們可以使用LinkedHashMap
的建構子將HashMap
轉換為我們想要的型別:
new LinkedHashMap<>(map
.entrySet()
.stream()
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)));
但是,由於這會建立兩個地圖實例**來實現我們的目標,因此首選初始方法。**
4. 使用Collectors.groupingBy()
方法
我們可以使用Collectors.groupingBy()
方法的重載來指定分組收集到的對應:
static <T, K, D, A, M extends Map<K, D>> Collector<T, ?, M>
groupingBy(Function<? super T, ? extends K> classifier, Supplier<M> mapFactory,
Collector<? super T, A, D> downstream)
假設我們有一張現有的城市到國家條目地圖:
Map<String, String> cityToCountry = Map.of("Paris", "France", "Nice", "France", "Madrid", "Spain");
但是,我們希望按國家/地區對城市進行分組。因此,我們將groupingBy()
與collect()
方法結合使用:
Map<String, Set<String>> countryToCities = cityToCountry
.entrySet()
.stream()
.collect(Collectors.groupingBy(Map.Entry::getValue, LinkedHashMap::new, Collectors.mapping(Map.Entry::getKey, Collectors.toSet())));
assertThat(countryToCities)
.isExactlyInstanceOf(LinkedHashMap.class)
.containsOnly(entry("France", Set.of("Paris", "Nice")), entry("Spain", Set.of("Madrid")));
我們使用Map.Entry::getValue
方法參考作為classifier
函數來按國家/地區進行分組。我們透過使用mapFactory
的LinkedHashMap::new
來聲明所需的映射以將分組收集到其中。最後,我們利用Collectors.mapping()
方法作為downstream
收集器,從條目中提取鍵以收集到每個集合中。
5. 使用*put()*方法
我們可以使用終端forEach()
操作和put()
方法將串流收集到現有的LinkedHashMap
中:
Map<Integer, String> result = new LinkedHashMap<>();
map
.entrySet()
.stream()
.forEach(entry -> result.put(entry.getKey(), entry.getValue()));
或者,我們可以完全避免串流並使用可用於Set
物件的forEach()
:
map
.entrySet()
.forEach(entry -> result.put(entry.getKey(), entry.getValue()));
為了進一步簡化,我們可以直接在地圖上使用forEach()
:
map.forEach((k, v) -> result.put(k, v));
然而,我們應該注意到,這些中的每一個都透過修改現有的映射將副作用操作引入我們的函數式程式設計中。因此,使用更命令式的風格會更適合:
for (Map.Entry<Integer, String> entry : map.entrySet()) {
result.put(entry.getKey(), entry.getValue());
}
我們使用增強的for
迴圈來迭代並將每個條目中的鍵值加入現有的LinkedHashMap
中。
6. 使用LinkedHashMap
的建構函數
如果我們想簡單地將映射轉換為LinkedHashMap
,則不需要串流傳輸條目來執行此操作。我們可以使用LinkedHashMap
的建構子簡單地轉換映射:
new LinkedHashMap<>(map);
七、結論
在本文中,我們探索了將映射條目流收集到LinkedHashMap.
我們探索了使用不同的終端操作和串流媒體替代方案來實現我們的目標。
與往常一樣,本文中使用的程式碼範例可以在 GitHub 上找到。