Note: The title <> is replaced with "", and the title contains <> and will be swallowed due to bugs.
background
During the development process, we will inevitably encounter sometimes when we need to convert a List into a Map or Map into a List. We can use a rough way to convert it, but this is not elegant enough, and the performance is not very high when there is too much data.
If you use Lambda frequently, you can know how convenient this syntax sugar is, which can make the code very concise. This article is used to explain the use of Lambda syntax of Stream streams to elegantly perform List and Map interchange operations and analyze its performance differences.
Some simple methods are not analyzed, such as map(), peek(), filter() and other methods, mainly focusing on analyzing the toMap() method of collect().
Lambda syntax application example of Stream stream
1. Define the UserDto to operate
First define a UserDto for direct subsequent use, and its code is as follows:
public class UserDto { private String name; private String sex; private String job; @Override public String toString() { return "{\"name\":\"" + name + "\",\"sex\":\"" + sex + "\",\"job\":\"" + job + "\"}"; } // Other properties, getter and setter methods are ignored}
2. Convert List to Map
There are many ways to convert List to Map. Any conversion can be completed using foreach, but in this article, we will share several traversal operations.
List "UserDto" converted to Map "String, UserDto"
First, let’s share the simplest conversion:
Convert List<UserDto> to use UserDto's name as Key, and UserDto is used as Value Map operation, that is, Map<String, UserDto> form.
The code is as follows:
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); (userList); // Use stream to convert List to Map Map<String, UserDto> userMap = () .collect((UserDto::getName, dto2 -> dto2)); (userMap); } } -------------Print results------------- [{"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" converted to Map "String, Map "String, Object"
Next, let’s share the Lambda operation in the form of List<UserDto> to Map<String, Map<String, Object>>:
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); (userList); // Use stream to convert List to Map Map<String, Map<String, Object>> userMap = () .collect((UserDto::getName, dto2 -> new HashMap<String, Object>(){{ put("name", ()); put("sex", ()); put("job", ());}})); (userMap); } } -------------Print results------------- [{"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" to Map "String, String"
Next, let’s share the Lambda operation of converting List<UserDto> into Map<String, String>. Of course, the String generics in Map can also be Integer, Long or even other types. Just replace them accordingly in the following way:
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); (userList); // Use stream to convert List to Map Map<String, String> userMap = () .collect((UserDto::getName, UserDto::getSex)); (userMap); } } -------------Print results------------- [{"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"" to Map "String, UserDto"
From List<Map<String, Object>> to Map<String, UserDto>, the String in the Map can also be Long, Integer or other types:
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 = (userMap1, userMap2, userMap3, userMap4); (userList); // Use stream to convert List to Map Map<String, UserDto> userMap = () .collect((map1 -> (String) ("name"), map2 -> new UserDto((String) ("name"), (String) ("sex"), (String) ("job")))); (userMap); } } -------------Print results------------- [{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"" to Map "String, String"
In the operation of List<Map<String, Object>> to Map<String, String>, the String in the Map can also be of Long, Integer or other types:
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 = (userMap1, userMap2, userMap3, userMap4); (userList); // Use stream to convert List to Map Map<String, String> userMap = () .collect((map1 -> (String) ("name"), map2 -> (String) ("sex"))); (userMap); } } -------------Print results------------- [{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"" to Map "String, Map "String, Object""
In the operation from List<Map<String, Object>> to Map<String, Map<String, Object>>, the String in the Map can also be Long, Integer or other types:
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 = (userMap1, userMap2, userMap3, userMap4); (userList); // Use stream to convert List to Map Map<String, Map<String, Object>> userMap = () .collect((map1 -> (String) ("name"), map2 -> map2)); (userMap); } } -------------Print results------------- [{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" to Map "String, List "Map"
To convert from List to Map>, group according to a value in the Map:
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 = (userMap1, userMap2, userMap3, userMap4); (userList); // Use stream to convert List to Map Map<String, List<Map<String, Object>>> userMap = () .collect((map1 -> (String) ("sex"))); (userMap); } } -------------Print results------------- [{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}]}
Performance Description
It should be noted that Stream uses stream processing and also has usage restrictions, such as initialization time and performance limitations:
- Initialization time: When the system uses Stream stream for the first time, it takes several dozen milliseconds if the initialization time is within 1W of data. If it is within 10W of data, it takes about 100 milliseconds if the initialization time is within 10W of data, it takes about 1000 milliseconds if the initialization time of 1000W of data, and it takes about 2500 milliseconds if the initialization time of foreach is similar to the subsequent time;
- Operational performance: The time spent on the data volume below 1W level is similar. The performance of Stream streams within 10W data is 1/2 of the foreach. The performance of Stream streams within 100W data is 3/5 of the foreach. At the 1000W data level, Stream has become about twice that of Foreach. At the 1000W data level, the initial running time remains at about 1400 milliseconds. Later, it runs to 6000 milliseconds or even 7000 milliseconds. I don’t know if it is caused by GC.
Therefore, when using Stream, it is suitable for low data volume. When the data magnitude is below 1W, both Stream streams and foreach can be used, and the performance difference is not large. When it reaches 10W-100W, foreach should be used faster performance; when it reaches 1000W, it should be used foreach or other big data analysis frameworks.
Using the above method, the 20 average running time schedule (only represents the specification CPU running efficiency of the native I5-8400 2.8Ghz-2.81Ghz):
Operation mode |
Data magnitude |
Initialization time (ms) |
Initialized Average operating efficiency (ms) |
foreach |
1W |
38 |
1 |
Stream stream |
1W |
1 |
1 |
foreach |
10W |
28 |
6 |
Stream stream |
10W |
54 |
12 |
foreach |
100W |
139 |
111 |
Stream stream |
100W |
1300 |
181 |
foreach |
1000W |
2500 |
3500 |
Stream stream |
1000W |
1130 |
6000 |
Summarize
The above is personal experience. I hope you can give you a reference and I hope you can support me more.