Java使用Stream流的Lambda語法進(jìn)行List轉(zhuǎn)Map的操作方式
注:標(biāo)題的<>被替換成了《》,標(biāo)題帶有<>會因為Bug被吞。
背景
在平時開發(fā)過程中難免會碰到有些時候需要將一個List轉(zhuǎn)成Map又或者是將Map轉(zhuǎn)成List,我們可以采用粗暴的方式來進(jìn)行轉(zhuǎn)換,但這樣一是不夠優(yōu)雅,二是數(shù)據(jù)過多的時候性能不是很高。
Lambda如果平時經(jīng)常使用就可以知道這種語法糖有多方便使用,可以讓代碼變得十分簡潔,而本篇便是用來說明使用Stream流的Lambda語法來優(yōu)雅的進(jìn)行List和Map的互轉(zhuǎn)操作,并分析其性能差異。
一些簡單的便不做分析了,比如map()、peek()、filter()等方法,主要著重分析collect()的toMap()方法。
Stream流的Lambda語法應(yīng)用實例
1、定義要操作的UserDto
先定義一個UserDto以便直接后續(xù)使用,其代碼如下:
public class UserDto { private String name; private String sex; private String job; @Override public String toString() { return "{\"name\":\"" + name + "\",\"sex\":\"" + sex + "\",\"job\":\"" + job + "\"}"; } // 后面其它的屬性和getter、setter方法都忽略 }
2、List轉(zhuǎn)成Map
List轉(zhuǎn)成Map有很多方式,使用foreach的方式什么轉(zhuǎn)換都可以完成,但在本篇將會分享幾個遍歷的操作。
List《UserDto》轉(zhuǎn)成Map《String, UserDto》
首先分享一下最簡單的轉(zhuǎn)換:
由List<UserDto>轉(zhuǎn)成以UserDto的name當(dāng)成Key,而UserDto當(dāng)成Value的Map操作,即Map<String, UserDto>形式。
代碼如下:
public class MainTest { public static void main(String[] args) { UserDto userDto1 = new UserDto("test1", "man", "worker1"); UserDto userDto2 = new UserDto("test2", "woman", "worker2"); UserDto userDto3 = new UserDto("test3", "woman", "worker2"); UserDto userDto4 = new UserDto("test4", "man", "worker3"); List<UserDto> userList = Arrays .asList(userDto1, userDto2, userDto3, userDto4); System.out.println(userList); // 使用stream流將List轉(zhuǎn)成Map Map<String, UserDto> userMap = userList.stream() .collect(Collectors.toMap(UserDto::getName, dto2 -> dto2)); System.out.println(userMap); } } -------------打印結(jié)果------------- [{"name":"test1","sex":"man","job":"worker1"}, {"name":"test2","sex":"woman","job":"worker2"}, {"name":"test3","sex":"woman","job":"worker2"}, {"name":"test4","sex":"man","job":"worker3"}] {test4={"name":"test4","sex":"man","job":"worker3"},test2={"name":"test2","sex":"woman","job":"worker2"}, test3={"name":"test3","sex":"woman","job":"worker2"},test1={"name":"test1","sex":"man","job":"worker1"}}
List《UserDto》轉(zhuǎn)成Map《String, Map《String, Object》》
接下來分享下將List<UserDto>轉(zhuǎn)成Map<String, Map<String, Object>>形式的Lambda操作:
public class MainTest { public static void main(String[] args) { UserDto userDto1 = new UserDto("test1", "man", "worker1"); UserDto userDto2 = new UserDto("test2", "woman", "worker2"); UserDto userDto3 = new UserDto("test3", "woman", "worker2"); UserDto userDto4 = new UserDto("test4", "man", "worker3"); List<UserDto> userList = Arrays .asList(userDto1, userDto2, userDto3, userDto4); System.out.println(userList); // 使用stream流將List轉(zhuǎn)成Map Map<String, Map<String, Object>> userMap = userList.stream() .collect(Collectors.toMap(UserDto::getName, dto2 -> new HashMap<String, Object>(){{ put("name", dto2.getName()); put("sex", dto2.getSex()); put("job", dto2.getJob());}})); System.out.println(userMap); } } -------------打印結(jié)果------------- [{"name":"test1","sex":"man","job":"worker1"}, {"name":"test2","sex":"woman","job":"worker2"}, {"name":"test3","sex":"woman","job":"worker2"}, {"name":"test4","sex":"man","job":"worker3"}] {test4={sex=man, name=test4, job=worker3}, test2={sex=woman, name=test2, job=worker2}, test3={sex=woman, name=test3, job=worker2}, test1={sex=man, name=test1, job=worker1}}
List《UserDto》轉(zhuǎn)Map《String, String》
接下來分享下將List<UserDto>轉(zhuǎn)成Map<String, String>形式的Lambda操作,當(dāng)然Map中String泛型也可以是Integer、Long甚至其它的類型,按照下面的方式進(jìn)行相應(yīng)的替換就行了:
public class MainTest { public static void main(String[] args) { UserDto userDto1 = new UserDto("test1", "man", "worker1"); UserDto userDto2 = new UserDto("test2", "woman", "worker2"); UserDto userDto3 = new UserDto("test3", "woman", "worker2"); UserDto userDto4 = new UserDto("test4", "man", "worker3"); List<UserDto> userList = Arrays .asList(userDto1, userDto2, userDto3, userDto4); System.out.println(userList); // 使用stream流將List轉(zhuǎn)成Map Map<String, String> userMap = userList.stream() .collect(Collectors.toMap(UserDto::getName, UserDto::getSex)); System.out.println(userMap); } } -------------打印結(jié)果------------- [{"name":"test1","sex":"man","job":"worker1"}, {"name":"test2","sex":"woman","job":"worker2"}, {"name":"test3","sex":"woman","job":"worker2"}, {"name":"test4","sex":"man","job":"worker3"}] {test4=man, test2=woman, test3=woman, test1=man}
List《Map《String, Object》》轉(zhuǎn)Map《String, UserDto》
由List<Map<String, Object>>轉(zhuǎn)Map<String, UserDto>操作中,Map中的String也可以是Long、Integer或者其它的類型:
public class MainTest { public static void main(String[] args) { Map<String, Object> userMap1 = new HashMap<String, Object>(8) {{ put("name", "test1");put("sex", "man");put("job", "worker1"); }}; Map<String, Object> userMap2 = new HashMap<String, Object>(8) {{ put("name", "test2");put("sex", "woman");put("job", "worker2"); }}; Map<String, Object> userMap3 = new HashMap<String, Object>(8) {{ put("name", "test3");put("sex", "woman");put("job", "worker2"); }}; Map<String, Object> userMap4 = new HashMap<String, Object>(8) {{ put("name", "test4");put("sex", "man");put("job", "worker3"); }}; List<Map<String, Object>> userList = Arrays.asList(userMap1, userMap2, userMap3, userMap4); System.out.println(userList); // 使用stream流將List轉(zhuǎn)成Map Map<String, UserDto> userMap = userList.stream() .collect(Collectors.toMap(map1 -> (String) map1.get("name"), map2 -> new UserDto((String) map2.get("name"), (String) map2.get("sex"), (String) map2.get("job")))); System.out.println(userMap); } } -------------打印結(jié)果------------- [{name=test1, job=worker1, sex=man}, {name=test2, job=worker2, sex=woman}, {name=test3, job=worker2, sex=woman}, {name=test4, job=worker3, sex=man}] {test4={"name":"test4","sex":"man","job":"worker3"}, test2={"name":"test2","sex":"woman","job":"worker2"}, test3={"name":"test3","sex":"woman","job":"worker2"}, test1={"name":"test1","sex":"man","job":"worker1"}}
List《Map《String, Object》》轉(zhuǎn)Map《String, String》
由List<Map<String, Object>>轉(zhuǎn)Map<String, String>操作中,Map中的String也可以是Long、Integer或者其它的類型:
public class MainTest { public static void main(String[] args) { Map<String, Object> userMap1 = new HashMap<String, Object>(8) {{ put("name", "test1");put("sex", "man");put("job", "worker1"); }}; Map<String, Object> userMap2 = new HashMap<String, Object>(8) {{ put("name", "test2");put("sex", "woman");put("job", "worker2"); }}; Map<String, Object> userMap3 = new HashMap<String, Object>(8) {{ put("name", "test3");put("sex", "woman");put("job", "worker2"); }}; Map<String, Object> userMap4 = new HashMap<String, Object>(8) {{ put("name", "test4");put("sex", "man");put("job", "worker3"); }}; List<Map<String, Object>> userList = Arrays.asList(userMap1, userMap2, userMap3, userMap4); System.out.println(userList); // 使用stream流將List轉(zhuǎn)成Map Map<String, String> userMap = userList.stream() .collect(Collectors.toMap(map1 -> (String) map1.get("name"), map2 -> (String) map2.get("sex"))); System.out.println(userMap); } } -------------打印結(jié)果------------- [{name=test1, job=worker1, sex=man}, {name=test2, job=worker2, sex=woman}, {name=test3, job=worker2, sex=woman}, {name=test4, job=worker3, sex=man}] {test4=man, test2=woman, test3=woman, test1=man}
List《Map《String, Object》》轉(zhuǎn)Map《String, Map《String, Object》》
由List<Map<String, Object>>轉(zhuǎn)Map<String, Map<String, Object>>操作中,Map中的String也可以是Long、Integer或者其它的類型:
public class MainTest { public static void main(String[] args) { Map<String, Object> userMap1 = new HashMap<String, Object>(8) {{ put("name", "test1");put("sex", "man");put("job", "worker1"); }}; Map<String, Object> userMap2 = new HashMap<String, Object>(8) {{ put("name", "test2");put("sex", "woman");put("job", "worker2"); }}; Map<String, Object> userMap3 = new HashMap<String, Object>(8) {{ put("name", "test3");put("sex", "woman");put("job", "worker2"); }}; Map<String, Object> userMap4 = new HashMap<String, Object>(8) {{ put("name", "test4");put("sex", "man");put("job", "worker3"); }}; List<Map<String, Object>> userList = Arrays.asList(userMap1, userMap2, userMap3, userMap4); System.out.println(userList); // 使用stream流將List轉(zhuǎn)成Map Map<String, Map<String, Object>> userMap = userList.stream() .collect(Collectors.toMap(map1 -> (String) map1.get("name"), map2 -> map2)); System.out.println(userMap); } } -------------打印結(jié)果------------- [{name=test1, job=worker1, sex=man}, {name=test2, job=worker2, sex=woman}, {name=test3, job=worker2, sex=woman}, {name=test4, job=worker3, sex=man}] {test4={name=test4, job=worker3, sex=man}, test2={name=test2, job=worker2, sex=woman}, test3={name=test3, job=worker2, sex=woman}, test1={name=test1, job=worker1, sex=man}}
List《Map》轉(zhuǎn)Map《String, List《Map》》
由List轉(zhuǎn)Map>,根據(jù)Map中的某個值進(jìn)行分組:
public class MainTest { public static void main(String[] args) { Map<String, Object> userMap1 = new HashMap<String, Object>(8) {{ put("name", "test1");put("sex", "man");put("job", "worker1"); }}; Map<String, Object> userMap2 = new HashMap<String, Object>(8) {{ put("name", "test2");put("sex", "woman");put("job", "worker2"); }}; Map<String, Object> userMap3 = new HashMap<String, Object>(8) {{ put("name", "test3");put("sex", "woman");put("job", "worker2"); }}; Map<String, Object> userMap4 = new HashMap<String, Object>(8) {{ put("name", "test4");put("sex", "man");put("job", "worker3"); }}; List<Map<String, Object>> userList = Arrays.asList(userMap1, userMap2, userMap3, userMap4); System.out.println(userList); // 使用stream流將List轉(zhuǎn)成Map Map<String, List<Map<String, Object>>> userMap = userList.stream() .collect(Collectors.groupingBy(map1 -> (String) map1.get("sex"))); System.out.println(userMap); } } -------------打印結(jié)果------------- [{name=test1, job=worker1, sex=man}, {name=test2, job=worker2, sex=woman}, {name=test3, job=worker2, sex=woman}, {name=test4, job=worker3, sex=man}] {woman=[{name=test2, job=worker2, sex=woman}, {name=test3, job=worker2, sex=woman}], man=[{name=test1, job=worker1, sex=man}, {name=test4, job=worker3, sex=man}]}
性能說明
需要注意的是Stream使用流處理也是有使用限制的,比如初始化時間和性能限制:
- 初始化時間:系統(tǒng)第一次使用Stream流的時候初始化時間如果是1W數(shù)據(jù)以內(nèi)的需要幾十毫秒,如果是10W數(shù)據(jù)以內(nèi)的初始化需要100毫秒左右,100W初始化需要1000毫秒左右,1000W初始化則需要2500毫秒左右,而foreach的初始化時間和后續(xù)的時間是差不多的;
- 運(yùn)行性能:數(shù)據(jù)量在1W級別以下的時間花費(fèi)差不多,10W數(shù)據(jù)以內(nèi)的Stream流比性能是foreach的1/2,100W數(shù)據(jù)以內(nèi)的Stream流性能是foreach的3/5,而到了1000W數(shù)據(jù)量級下Stream又變成了foreach的一倍左右,foreach到了1000W數(shù)據(jù)量級下最開始運(yùn)行時間還保持在1400毫秒左右,到了后面則跑到了6000毫秒甚至7000毫秒,不知道是不是因為GC導(dǎo)致的。
因此使用Stream時適用于低數(shù)據(jù)量的情況,當(dāng)數(shù)據(jù)量級在1W以下是Stream流和foreach都可以使用,性能差別不大;到了10W-100W時應(yīng)該使用foreach性能更快;而到了1000W量級的情況下就該使用Stream或者其它的大數(shù)據(jù)解析框架了。
使用上述方式的20次平均運(yùn)行時間表(僅代表本機(jī)I5-8400 2.8Ghz-2.81Ghz的規(guī)格CPU運(yùn)行效率):
運(yùn)行方式 | 數(shù)據(jù)量級 | 初始化時間(ms) | 初始化后的 平均運(yùn)行效率(ms) |
foreach | 1W | 38 | 1 |
stream流 | 1W | 1 | 1 |
foreach | 10W | 28 | 6 |
stream流 | 10W | 54 | 12 |
foreach | 100W | 139 | 111 |
stream流 | 100W | 1300 | 181 |
foreach | 1000W | 2500 | 3500 |
stream流 | 1000W | 1130 | 6000 |
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Eclipse 開發(fā)java 出現(xiàn)Failed to create the Java Virtual Machine錯誤
這篇文章主要介紹了Eclipse 開發(fā)java 出現(xiàn)Failed to create the Java Virtual Machine錯誤解決辦法的相關(guān)資料,需要的朋友可以參考下2017-04-04Spring?boot?運(yùn)用策略模式實現(xiàn)避免多次使用if的操作代碼
這篇文章主要介紹了Spring?boot?運(yùn)用策略模式實現(xiàn),避免多次使用if,使用策略模式后,新加一種支付策略時,只需要在策略枚舉中添加新加的策略信息,外加一個策略類即可,而不再需要添加新的if判斷,需要的朋友可以參考下2022-08-08SpringAOP 構(gòu)造注入的實現(xiàn)步驟
這篇文章主要介紹了SpringAOP_構(gòu)造注入的實現(xiàn)步驟,幫助大家更好的理解和學(xué)習(xí)使用spring框架,感興趣的朋友可以了解下2021-05-05Mybatis日志參數(shù)快速替換占位符工具的詳細(xì)步驟
這篇文章主要介紹了Mybatis日志參數(shù)快速替換占位符工具的詳細(xì)步驟,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-08-08Hadoop之NameNode Federation圖文詳解
今天小編就為大家分享一篇關(guān)于Hadoop之NameNode Federation圖文詳解,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧2019-01-01Java?IO流之StringWriter和StringReader用法分析
這篇文章主要介紹了Java?IO流之StringWriter和StringReader用法分析,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-12-12SpringBoot應(yīng)用自定義logback日志詳解
默認(rèn)情況下,SpringBoot內(nèi)部使用logback作為系統(tǒng)日志實現(xiàn)的框架,將日志輸出到控制臺,不會寫到日志文件。本篇文章主要講解下如何自定義logabck.xml以及對logback文件中配置做一個詳解,需要的可以參考一下2022-10-10Java8并發(fā)新特性CompletableFuture
這篇文章主要介紹了Java8并發(fā)新特性CompletableFuture,CompletableFuture針對Future接口做了改進(jìn),相比Callable/Runnable接口它支持多任務(wù)進(jìn)行鏈?zhǔn)秸{(diào)用、組合、多任務(wù)并發(fā)處理,下面文章更多相關(guān)內(nèi)容得介紹,需要的小伙伴可以參考一下2022-06-06