使用stream的Collectors.toMap()方法常見的問題及解決
使用stream的Collectors.toMap()方法常見問題
java8開始的流式編程很大程度上簡化了我們的代碼,提高了開發(fā)效率。
我們經(jīng)常會使用到stream的Collectors.toMap()來將List轉換Map
在使用過程中有兩個小坑需要注意
1、java.lang.IllegalStateException: Duplicate key
2、java.lang.NullPointerException
第一個是由于在List轉Map過程中Map集合的key重復導致的;
第二個是由于在List轉Map過程中Map集合的value有null導致的(當存在value值為空時,使用Collectors.toMap()會報NPE,因為底層調用了Map的merge方法,而map方法規(guī)定了此處的vlue不能為null,從而拋出空指針異常);
解決方案
1、Collectors.toMap(dto ->key值 , dto -> dto,(v1,v2) -> v1)
在后面添加(v1,v2)->v1 指定選取第一個值 當key值重復的時候,根據(jù)情況而定選取第一個還是第二個)
2、自定義一個Map來接收,不使用Collectors.toMap()
第一種情況示例:
import com.google.common.collect.Lists; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import lombok.Data; public class Test { private static List<User> userList = Lists.newArrayList(); @Data public static class User { private String userCode; private String userName; } /** * 初始化數(shù)據(jù) * (這里的userCode=10002重復) */ public static void initData() { User user1 = new User(); user1.setUserCode("10001"); user1.setUserName("張三"); User user2 = new User(); user2.setUserCode("10002"); user2.setUserName("李四"); User user3 = new User(); user3.setUserCode("10002"); user3.setUserName("王五"); userList.add(user1); userList.add(user2); userList.add(user3); } public static void main(String[] args) { initData(); //反例 // Map<String, String> userMap = userList.stream().collect(Collectors.toMap(User::getUserCode, User::getUserName)); //正例,在后面添加(u1,u2)->u1 指定選取第一個值 當key值重復的時候,根據(jù)情況而定選取第一個還是第二個 Map<String, String> userMap = userList.stream().collect(Collectors.toMap(User::getUserCode, User::getUserName, (u1, u2) -> u1)); System.out.println(userMap); } }
第二種情況示例:
import com.google.common.collect.Lists; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import lombok.Data; public class Test { private static List<User> userList = Lists.newArrayList(); @Data public static class User { private String userCode; private String userName; } /** * 初始化數(shù)據(jù) * (這里的userCode=10003的userName為空) */ public static void initData() { User user1 = new User(); user1.setUserCode("10001"); user1.setUserName("張三"); User user2 = new User(); user2.setUserCode("10002"); user2.setUserName("李四"); User user3 = new User(); user3.setUserCode("10003"); user3.setUserName(null); userList.add(user1); userList.add(user2); userList.add(user3); } public static void main(String[] args) { initData(); //反例 // Map<String, String> userMap = userList.stream().collect(Collectors.toMap(User::getUserCode, User::getUserName)); //正例 (如果對轉換后的順序有要求,這里還可以使用LinkedHashMap) Map<String, String> userMap = userList.stream().collect(HashMap::new, (map, user) -> map.put(user.getUserCode(), user.getUserName()), HashMap::putAll); System.out.println(userMap); } }
Stream ToMap(Collectors.toMap) 實踐
Requirements
List TO Map
List Stream 轉換 Map時向collect()方法中傳遞Collector對象,對象由Collectors.toMap()方法返回。
如下實現(xiàn)List轉換為Map
List<GroupBrandCateBO> list = new ArrayList<>( ? ? ? Arrays.asList( ? ? ? ? ? ? ? new GroupBrandCateBO("v1", "g1", "b1"), ? ? ? ? ? ? ? new GroupBrandCateBO("v1", "g1", "b1"), ? ? ? ? ? ? ? new GroupBrandCateBO("v3", "g3", "b3") ? ? ? ) ); Map<String, String> map = list.stream().collect(Collectors.toMap(item -> item.getVersion(), item -> item.getGroupCode(), (oldVal, currVal) -> oldVal, LinkedHashMap::new));? System.out.println(map.getClass()); Map<String, String> map0 = list.stream().collect(Collectors.toMap(item -> item.getVersion(), item -> item.getGroupCode(), (oldVal, currVal) -> oldVal)); System.out.println(map0.getClass()); System.out.println(map0.toString()); Map<String, String> map1 = list.stream().collect(Collectors.toMap(GroupBrandCateBO::getVersion, GroupBrandCateBO::getGroupCode)); System.out.println(map1.toString());
Console
class java.util.LinkedHashMap
class java.util.HashMap
{v1=g1, v3=g3}
Exception in thread “main” java.lang.IllegalStateException: Duplicate key g1
at java.util.stream.Collectors.lambda$throwingMerger$0(Collectors.java:133)
…
問題分析
toMap()函數(shù)重載:
- 未指定合并函數(shù)mergeFunction情況下,傳入throwingMerger()返回BinaryOperator對象,當出現(xiàn)key重復時,調用合并函數(shù)!
- 未指定Supplier實例情況下,默認生成HashMap實例。
public static <T, K, U> Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Function<? super T, ? extends U> valueMapper) { ? ? return toMap(keyMapper, valueMapper, throwingMerger(), HashMap::new); } public static <T, K, U> Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Function<? super T, ? extends U> valueMapper, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? BinaryOperator<U> mergeFunction) { ? ? return toMap(keyMapper, valueMapper, mergeFunction, HashMap::new); } public 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> mapSupplier) { ? ? BiConsumer<M, T> accumulator ? ? ? ? ? ? = (map, element) -> map.merge(keyMapper.apply(element), ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? valueMapper.apply(element), mergeFunction); ? ? return new CollectorImpl<>(mapSupplier, accumulator, mapMerger(mergeFunction), CH_ID); } private static <T> BinaryOperator<T> throwingMerger() { ? ? return (u,v) -> { throw new IllegalStateException(String.format("Duplicate key %s", u)); }; }
補充
關于合并函數(shù)
List<GroupBrandCateBO> list = new ArrayList<>( ? ? ? ?Arrays.asList( ? ? ? ? ? ? ? ?new GroupBrandCateBO("v1", "g1", "b1"), ? ? ? ? ? ? ? ?new GroupBrandCateBO("v1", "g2", "b2"), ? ? ? ? ? ? ? ?new GroupBrandCateBO("v1", "g2", "b2"), ? ? ? ? ? ? ? ?new GroupBrandCateBO("v3", "g3", "b3") ? ? ? ?) ); Map<String, String> map00 = list.stream().collect(Collectors.toMap(item -> item.getVersion(), item -> item.getGroupCode(), (oldVal, currVal) -> currVal)); Map<String, String> map01 = list.stream().collect(Collectors.toMap(item -> item.getVersion(), item -> item.getGroupCode(), (oldVal, currVal) -> oldVal + currVal)); System.out.println(map00.toString()); System.out.println(map01.toString());
Console
{v1=g2, v3=g3}
{v1=g1g2g2, v3=g3}
傳入Lambda表達式將轉化為BinaryOperator<U> mergeFunction對象,合并處理value,非Key!?。?/p>
比如:
(oldVal, currVal) -> currVal) // key相同時當前值替換原始值 (oldVal, currVal) -> oldVal + currVal //key相同時保留原始值和當前值
總結
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
Intellij idea使用Statistic統(tǒng)計代碼行數(shù)的方法
這篇文章主要介紹了Intellij idea使用Statistic統(tǒng)計代碼行數(shù)的方法,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-04-04關于IDEA2020.1新建項目maven PKIX 報錯問題解決方法
這篇文章主要介紹了關于IDEA2020.1新建項目maven PKIX 報錯問題解決方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-06-06Sharding Jdbc批量操作引發(fā)fullGC解決
這篇文章主要為大家介紹了Sharding Jdbc批量操作引發(fā)fullGC解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-11-11