java8的lambda中的map相關操作
一 原文連結:https://blog.csdn.net/w605283073/article/details/82987157
1. 介紹
本入門教程將介紹Java8中如何合併兩個map。
更具體說來,我們將研究不同的合併方案,包括Map含有重複元素的情況。
2. 初始化
我們定義兩個map例項
private static Map<String, Employee> map1 = new HashMap<>(); private static Map<String, Employee> map2 = new HashMap<>();
Employee類
public class Employee {
private Long id;
private String name;
// 此處省略構造方法, getters, setters方法
}
然後往map中存入一些資料
Employee employee1 = new Employee(1L, "Henry"); map1.put(employee1.getName(), employee1); Employee employee2 = new Employee(22L, "Annie"); map1.put(employee2.getName(), employee2); Employee employee3 = new Employee(8L, "John"); map1.put(employee3.getName(), employee3); Employee employee4 = new Employee(2L, "George"); map2.put(employee4.getName(), employee4); Employee employee5 = new Employee(3L, "Henry"); map2.put(employee5.getName(), employee5);
特別需要注意的是employee1 和 employee5在map中有完全相同的key(name)。
3. Map.merge()
Java8為 java.util.Map介面新增了merge()函式。
merge() 函式的作用是: 如果給定的key之前沒設定value 或者value為null, 則將給定的value關聯到這個key上.
否則,通過給定的remaping函式計算的結果來替換其value。如果remapping函式的計算結果為null,將解除此結果。
First, let’s construct a new HashMap
首先,我們通過拷貝map1中的元素來構造一個新的HashMap
Map<String, Employee> map3 = new HashMap<>(map1);
然後引入merge函式和合並規則
map3.merge(key, value, (v1, v2) -> new Employee(v1.getId(),v2.getName())
最後對map2進行迭代將其元素合併到map3中
map2.forEach(
(key, value) -> map3.merge(key, value, (v1, v2) -> new Employee(v1.getId(),v2.getName())));
執行程式並列印結果如下:
John=Employee{id=8, name='John'}
Annie=Employee{id=22, name='Annie'}
George=Employee{id=2, name='George'}
Henry=Employee{id=1, name='Henry'}
最終,通過結果可以看出,實現了兩個map的合併,對重複的key也合併為同一個元素。
注意最後一個Employee的id來自map1而name來自map2.
原因是我們的merge函式的定義
(v1, v2) -> new Employee(v1.getId(), v2.getName())
4. Stream.concat()
Java8的Stream API 也為解決該問題提供了較好的解決方案。
首先需要將兩個map合為一個Stream。
Stream combined = Stream.concat(map1.entrySet().stream(), map2.entrySet().stream());
我們需要將entry sets作為引數,然後利用Collectors.toMap():將結果放到新的map中。
Map<String, Employee> result = combined.collect(
Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
該方法可以實現map的合併,但是有重複key會報IllegalStateException異常。
為了解決這個問題,我們需要加入lambda表示式merger作為第三個引數
(value1, value2) -> new Employee(value2.getId(), value1.getName())
當檢測到有重複Key時就會用到該lambda表示式。
現在把上面程式碼組合在一起:
Map<String, Employee> result = Stream.concat(map1.entrySet().stream(), map2.entrySet().stream())
.collect(Collectors.toMap(
Map.Entry::getKey,
Map.Entry::getValue,
(value1, value2) -> new Employee(value2.getId(), value1.getName())));
最終的結果
George=Employee{id=2, name='George'}
John=Employee{id=8, name='John'}
Annie=Employee{id=22, name='Annie'}
Henry=Employee{id=3, name='Henry'}
從結果可以看出重複的key “Henry”將合併為一個新的鍵值對,id取自map2,name取自map1。
5. Stream.of()
通過Stream.of()方法不需要藉助其他stream就可以實現map的合併。
Map<String, Employee> map3 = Stream.of(map1, map2)
.flatMap(map -> map.entrySet().stream())
.collect(Collectors.toMap(
Map.Entry::getKey,
Map.Entry::getValue,
(v1, v2) -> new Employee(v1.getId(), v2.getName())));
首先將map1和map2的元素合併為同一個流,然後再轉成map。通過使用v1的id和v2的name來解決重複key的問題。
map3的執行列印結果如下:
6. Simple Streaming
我們還可以藉助stream的管道操作來實現map合併。
Map<String, Employee> map3 = map2.entrySet()
.stream()
.collect(Collectors.toMap(
Map.Entry::getKey,
Map.Entry::getValue,
(v1, v2) -> new Employee(v1.getId(), v2.getName()),
() -> new HashMap<>(map1)));
結果如下:
{John=Employee{id=8, name='John'},
Annie=Employee{id=22, name='Annie'},
George=Employee{id=2, name='George'},
Henry=Employee{id=1, name='Henry'}}
7. StreamEx
我們還可以使Stream API 的增強庫
Map<String, Employee> map3 = EntryStream.of(map1)
.append(EntryStream.of(map2))
.toMap((e1, e2) -> e1);
注意 (e1, e2) -> e1 表示式來處理重複key的問題,如果沒有該表示式依然會報IllegalStateException異常。
結果:
{George=Employee{id=2, name='George'},
John=Employee{id=8, name='John'},
Annie=Employee{id=22, name='Annie'},
Henry=Employee{id=1, name='Henry'}}
8 總結
本文使用了Map.merge(), Stream API, StreamEx 庫實現map的合併。
本文原始碼:https://github.com/eugenp/tutorials/tree/master/core-java-collections
二:Java8使List轉為Map
https://blog.csdn.net/hanerer1314/article/details/78826068
import com.yang.test.User;
import javax.jws.soap.SOAPBinding;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
public class Main {
public static void main(String[] args) {
List<User> userlist = new ArrayList<>();
for (int i = 0; i <10; i++) {
userlist.add(new User("張三"+i,i));
}
System.out.println(getAllages(userlist).size());
System.out.println(getUser2Map(userlist));
System.out.println(getUser2MapUser(userlist));
System.out.println(getUser2MapUser2(userlist));
System.out.println(getUser2MapUser3(userlist));
}
public static List<Integer> getAllages(List<User>userlist){
return userlist.stream().map(user -> user.getAge()).collect(Collectors.toList());
}
public static Map<Integer,String> getUser2Map(List<User>userlist){
return userlist.stream().collect(Collectors.toMap(User::getAge,User::getName));
}
public static Map<Integer,User> getUser2MapUser(List<User>userlist){
return userlist.stream().collect(Collectors.toMap(User::getAge,User-> User));
}
/**
* 比較優雅的寫法是這樣的
* @param userlist
* @return
*/
public static Map<Integer,User> getUser2MapUser2(List<User>userlist){
return userlist.stream().collect(Collectors.toMap(User::getAge, Function.identity()));
}
/**
* 重複key的情況下 簡單的使用後者覆蓋前者的
*/
public static Map<Integer,User> getUser2MapUser3(List<User>userlist){
return userlist.stream().collect(Collectors.toMap(User::getAge, Function.identity(),(key1,key2)->key2));
}
/**
*指定map的具體實現
* @param userlist
* @return
*/
public static Map<Integer,User> getUser2MapUser4(List<User>userlist){
return userlist.stream().collect(Collectors.toMap(User::getAge, Function.identity(),(key1,key2)->key2, LinkedHashMap::new));
}
}
Function.identity()用的預設的也可以是x->x 即value是user