SoFunction
Updated on 2025-05-07

Java uses Lambda syntax of Stream stream to perform List to Map operation method

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&lt;UserDto&gt; userList = Arrays
            .asList(userDto1, userDto2, userDto3, userDto4);
        (userList);
        // Use stream to convert List to Map        Map&lt;String, UserDto&gt; userMap = ()
            .collect((UserDto::getName, dto2 -&gt; 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&lt;UserDto&gt; userList = Arrays
            .asList(userDto1, userDto2, userDto3, userDto4);
        (userList);
        // Use stream to convert List to Map        Map&lt;String, Map&lt;String, Object&gt;&gt; userMap = ()
        .collect((UserDto::getName, dto2 -&gt;
                new HashMap&lt;String, Object&gt;(){{
                    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&lt;UserDto&gt; userList = Arrays
            .asList(userDto1, userDto2, userDto3, userDto4);
        (userList);
        // Use stream to convert List to Map        Map&lt;String, String&gt; 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&lt;String, Object&gt; userMap1 = new HashMap&lt;String, Object&gt;(8) {{
            put("name", "test1");put("sex", "man");put("job", "worker1");
        }};
        Map&lt;String, Object&gt; userMap2 = new HashMap&lt;String, Object&gt;(8) {{
            put("name", "test2");put("sex", "woman");put("job", "worker2");
        }};
        Map&lt;String, Object&gt; userMap3 = new HashMap&lt;String, Object&gt;(8) {{
            put("name", "test3");put("sex", "woman");put("job", "worker2");
        }};
        Map&lt;String, Object&gt; userMap4 = new HashMap&lt;String, Object&gt;(8) {{
            put("name", "test4");put("sex", "man");put("job", "worker3");
        }};
        List&lt;Map&lt;String, Object&gt;&gt; userList = (userMap1, userMap2, userMap3, userMap4);
        (userList);
        // Use stream to convert List to Map        Map&lt;String, UserDto&gt; userMap = ()
                .collect((map1 -&gt; (String) ("name"), map2 -&gt;
                        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&lt;String, Object&gt; userMap1 = new HashMap&lt;String, Object&gt;(8) {{
            put("name", "test1");put("sex", "man");put("job", "worker1");
        }};
        Map&lt;String, Object&gt; userMap2 = new HashMap&lt;String, Object&gt;(8) {{
            put("name", "test2");put("sex", "woman");put("job", "worker2");
        }};
        Map&lt;String, Object&gt; userMap3 = new HashMap&lt;String, Object&gt;(8) {{
            put("name", "test3");put("sex", "woman");put("job", "worker2");
        }};
        Map&lt;String, Object&gt; userMap4 = new HashMap&lt;String, Object&gt;(8) {{
            put("name", "test4");put("sex", "man");put("job", "worker3");
        }};
        List&lt;Map&lt;String, Object&gt;&gt; userList = (userMap1, userMap2, userMap3, userMap4);
        (userList);
        // Use stream to convert List to Map        Map&lt;String, String&gt; userMap = ()
                .collect((map1 -&gt; (String) ("name"), 
                    map2 -&gt; (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&lt;String, Object&gt; userMap1 = new HashMap&lt;String, Object&gt;(8) {{
            put("name", "test1");put("sex", "man");put("job", "worker1");
        }};
        Map&lt;String, Object&gt; userMap2 = new HashMap&lt;String, Object&gt;(8) {{
            put("name", "test2");put("sex", "woman");put("job", "worker2");
        }};
        Map&lt;String, Object&gt; userMap3 = new HashMap&lt;String, Object&gt;(8) {{
            put("name", "test3");put("sex", "woman");put("job", "worker2");
        }};
        Map&lt;String, Object&gt; userMap4 = new HashMap&lt;String, Object&gt;(8) {{
            put("name", "test4");put("sex", "man");put("job", "worker3");
        }};
        List&lt;Map&lt;String, Object&gt;&gt; userList = (userMap1, userMap2, userMap3, userMap4);
        (userList);
        // Use stream to convert List to Map        Map&lt;String, Map&lt;String, Object&gt;&gt; userMap = ()
        .collect((map1 -&gt; (String) ("name"), map2 -&gt; 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&lt;String, Object&gt; userMap1 = new HashMap&lt;String, Object&gt;(8) {{
            put("name", "test1");put("sex", "man");put("job", "worker1");
        }};
        Map&lt;String, Object&gt; userMap2 = new HashMap&lt;String, Object&gt;(8) {{
            put("name", "test2");put("sex", "woman");put("job", "worker2");
        }};
        Map&lt;String, Object&gt; userMap3 = new HashMap&lt;String, Object&gt;(8) {{
            put("name", "test3");put("sex", "woman");put("job", "worker2");
        }};
        Map&lt;String, Object&gt; userMap4 = new HashMap&lt;String, Object&gt;(8) {{
            put("name", "test4");put("sex", "man");put("job", "worker3");
        }};
        List&lt;Map&lt;String, Object&gt;&gt; userList = (userMap1, userMap2, userMap3, userMap4);
        (userList);
        // Use stream to convert List to Map        Map&lt;String, List&lt;Map&lt;String, Object&gt;&gt;&gt; userMap = ()
                .collect((map1 -&gt; (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.