In your case I would create the maps first and then loop through the elements in this list as shown:

Map<String, List<MyObject>> rows = new HashMap<>(); 
list.forEach(element -> rows.computeIfAbsent(element.personalId, s -> new ArrayList<>()).add(element));

You can use computeIfAbsent in order to create a new list/map as a value of the map before you can put your data in.


The same is with the second data type you created:

Map<String, Map<Integer, MyObject>> persons = new HashMap<>();
list.forEach(element -> persons.computeIfAbsent(element.personalId, s -> new HashMap<>()).put(element.rowNumber, element));

Here is a way to solve this with streams. But note that the objects must have a unique personId/rowNumber:

Map<String, List<MyObject>> rows = list.stream().collect(
        Collectors.toMap(element -> element.personalId, 
        element -> new ArrayList<MyObject>(Arrays.asList(element))));

As well as for the other map:

    Map<String, Map<Integer, MyObject>> persons = list.stream().collect(
            Collectors.toMap(e -> e.personalId, 
            e -> new HashMap<>(Map.of(e.rowNumber, e))));
Answer from Japhei on Stack Overflow
🌐
Baeldung
baeldung.com › home › java › java collections › java map › java collectors tomap
Java Collectors toMap | Baeldung
February 26, 2026 - In this article, we looked into the toMap() method of the Collectors class. It allows us to create a new Map from a Stream.
Top answer
1 of 2
9

In your case I would create the maps first and then loop through the elements in this list as shown:

Map<String, List<MyObject>> rows = new HashMap<>(); 
list.forEach(element -> rows.computeIfAbsent(element.personalId, s -> new ArrayList<>()).add(element));

You can use computeIfAbsent in order to create a new list/map as a value of the map before you can put your data in.


The same is with the second data type you created:

Map<String, Map<Integer, MyObject>> persons = new HashMap<>();
list.forEach(element -> persons.computeIfAbsent(element.personalId, s -> new HashMap<>()).put(element.rowNumber, element));

Here is a way to solve this with streams. But note that the objects must have a unique personId/rowNumber:

Map<String, List<MyObject>> rows = list.stream().collect(
        Collectors.toMap(element -> element.personalId, 
        element -> new ArrayList<MyObject>(Arrays.asList(element))));

As well as for the other map:

    Map<String, Map<Integer, MyObject>> persons = list.stream().collect(
            Collectors.toMap(e -> e.personalId, 
            e -> new HashMap<>(Map.of(e.rowNumber, e))));
2 of 2
2

Map<String, Map<Integer, List<MyObject>>> object using streams without using Collectors.groupingBy()

By looking at the map type, I can assume that a combination of personalId and rowNumber is not unique, i.e. there could be multiple occurrences of each combination (otherwise you don't need to group objects into lists). And there could be different rowNumber associated with each personalId. Only if these conclusions correct, this nested collection might have a very vague justification for existence.

Otherwise, you probably can substitute it multiple collections for different use-cases, for Map<String, MyObject> - object by id (if every id is unique):

Map<String, MyObject> objById = myList.stream()
    .collect(Collectors.toMap(
        MyObject::getPersonalId,
        Function.identity()
    ));

I'll proceed assuming that you really need such a nested collection.

Now, let's address the issue with groupingBy(). This collector uses internally Objects.requireNonNull() to make sure that a key produced by the classifier function is non-null.

If you tried to use and failed because of the hostility to null-keys, that implies that either personalId, or rowNumber, or both can be null.

Now let's make a small detour and pose the question of what does it imply if a property that considered to be significant (you're going to use personalId and rowNumber to access the data, hence they are definitely important) and null means first of all?

null signifies the absence of data and nothing else. If in your application null values have an additional special meaning, that's a design flaw. If properties that are significant for managing your data for some reason appear to be null you need to fix that.

You might claim that you're quite comfortable with null values. If so let pause for a moment and imagine a situation: person enters a restaurant, orders a soup and asks the waiter to bring them a fork instead of spoon (because of they have a negative experience with a spoon, and they are enough comfortable with fork).

null isn't a data, it's an indicator of the absence of data, storing null is an antipattern. If you're storing null it obtains a special meaning because you're forced to treat it separately.

To replace personalId and rowNumber that are equal to null with default values we need only one line of code.

public static void replaceNullWithDefault(List<MyObject> list,
                                          String defaultId,
                                          Integer defaultNum) {
    
    list.replaceAll(obj -> obj.getPersonalId() != null && obj.getRowNumber() != null ? obj :
        new MyObject(Objects.requireNonNullElse(obj.getPersonalId(), defaultId),
            Objects.requireNonNullElse(obj.getRowNumber(), defaultNum),
            obj.getDescription()));
}

After that can use the proper tool instead eating soup with a fork, I mean we can process the list data with groupingBy():

public static void main(String[] args) {
    List<MyObject> myList = new ArrayList<>(
        List.of(
            new MyObject("id1", 1, "desc1"),
            new MyObject("id1", 1, "desc2"),
            new MyObject("id1", 2, "desc3"),
            new MyObject("id1", 2, "desc4"),
            new MyObject("id2", 1, "desc5"),
            new MyObject("id2", 1, "desc6"),
            new MyObject("id2", 1, "desc7"),
            new MyObject(null, null, "desc8")
        ));
    
    replaceNullWithDefault(myList, "id0", 0); // replacing null values
    
    Map<String, Map<Integer, List<MyObject>>> byIdAndRow = myList // generating a map
        .stream()
        .collect(Collectors.groupingBy(
            MyObject::getPersonalId,
            Collectors.groupingBy(MyObject::getRowNumber)
        ));
    
    byIdAndRow.forEach((k, v) -> { // printing the map
        System.out.println(k);
        v.forEach((k1, v1) -> System.out.println(k1 + " -> " + v1));
    });
}

Output:

id0
0 -> [MyObject{'id0', 0, 'desc8'}]
id2
1 -> [MyObject{'id2', 1, 'desc5'}, MyObject{'id2', 1, 'desc6'}, MyObject{'id2', 1, 'desc7'}]
id1
1 -> [MyObject{'id1', 1, 'desc1'}, MyObject{'id1', 1, 'desc2'}]
2 -> [MyObject{'id1', 2, 'desc3'}, MyObject{'id1', 2, 'desc4'}]

A link to Online Demo

Now, please pay attention to the usage of groupingBy() did you notice its conciseness. That's the right tool which allows generating even such a clumsy nested map.

And now we're going to eat the soup with a fork! All null properties would be used as is:

public static void main(String[] args) {
    List<MyObject> myList = new ArrayList<>(
        List.of(
            new MyObject("id1", 1, "desc1"),
            new MyObject("id1", 1, "desc2"),
            new MyObject("id1", 2, "desc3"),
            new MyObject("id1", 2, "desc4"),
            new MyObject("id2", 1, "desc5"),
            new MyObject("id2", 1, "desc6"),
            new MyObject("id2", 1, "desc7"),
            new MyObject(null, null, "desc8")
        ));
    
    Map<String, Map<Integer, List<MyObject>>> byIdAndRow = myList // generating a map
        .stream()
        .collect(
            HashMap::new,
            (Map<String, Map<Integer, List<MyObject>>> mapMap, MyObject next) ->
                mapMap.computeIfAbsent(next.getPersonalId(), k -> new HashMap<>())
                    .computeIfAbsent(next.getRowNumber(), k -> new ArrayList<>())
                    .add(next),
            (left, right) -> right.forEach((k, v) -> left.merge(k, v,
                (oldV, newV) -> {
                    newV.forEach((k1, v1) -> oldV.merge(k1, v1,
                        (listOld, listNew) -> {
                            listOld.addAll(listNew);
                            return listOld;
                        }));
                    return oldV;
                }))
        );
    
    byIdAndRow.forEach((k, v) -> { // printing the map
        System.out.println(k);
        v.forEach((k1, v1) -> System.out.println(k1 + " -> " + v1));
    });
}

Output:

null
null -> [MyObject{'null', null, 'desc8'}]
id2
1 -> [MyObject{'id2', 1, 'desc5'}, MyObject{'id2', 1, 'desc6'}, MyObject{'id2', 1, 'desc7'}]
id1
1 -> [MyObject{'id1', 1, 'desc1'}, MyObject{'id1', 1, 'desc2'}]
2 -> [MyObject{'id1', 2, 'desc3'}, MyObject{'id1', 2, 'desc4'}]

A link to Online Demo

Discussions

Need help with .stream().map and Collectors.toMap()
So I have a Map normalMap and my method needs to first invert the keys&values and lastly return the map as Map Why not do both at the same time? return normalMap.entrySet().stream().collect(Collectors.toMap( e -> e.getValue().toString(), Map.Entry::getKey)); More on reddit.com
🌐 r/javahelp
5
2
November 14, 2021
java - Collect a Stream of objects into a Map - Stack Overflow
I have a csv file of user details which I will have to load into a HashMap by reading each line. This is done using a little help from Java 8 streams. Map users = new HashM... More on stackoverflow.com
🌐 stackoverflow.com
collections - Java 8 streams - collect and stream map of lists - Stack Overflow
I have a Map of Lists, and would like to collect all the values and then stream on the collected List, so given:- Map effectiveDatePublicationM... More on stackoverflow.com
🌐 stackoverflow.com
Why does the List interface have forEach, but not map?
why isn't every List a Stream? To answer this part of the question, it's because a stream is a fundamentally different datatype than a list. A list represents a collection of data, while a stream represents a pipeline for processing data. Streams can only be processed once, and are designed to perform multiple operations on some provided data. They don't store any intermediate results, and then do lazy processing once you specify a terminal operator (like toList() or forEach()). For example, if you had something like this: Stream a = List.of(1, 2, 3).stream(); Stream b = a.filter(n -> n > 1); Stream c = b.map(n -> String.valueOf(n)); List d = c.toList(); This is functionally identical to this: List d = List.of(1, 2, 3).stream() .filter(n -> n > 1) .map(n -> String.valueOf(n)) .toList(); If you inspected b, however, it would not contain any data about what elements were remaining, because the stream has not executed yet. Assigning the various steps of the stream along the way doesn't actually DO anything to the data, it just creates pointers to instances of the pipeline. As mentioned before, the pipeline can only be executed once, which means a stream is consumed when you perform a terminal operation on it. It also can't be executed if you chain it to another pipeline. If, in the example above, you tried to do b.toList(), you'd get an IllegalStateException, because b was already operated on. If you did c.toList(), you'd get a list of "2", "3". If you did c.toList() a second time, you'd once again get an IllegalStateExcecution, because c has already been consumed. The intermediate operators like map actually do nothing except modify the pipeline definition until you call toList at the end. Once you execute toList, then the pipeline operates in a lazy way, evaluating the data elements one at a time. So, to recap: List: collection of ordered data Stream: an operation pipeline definition More on reddit.com
🌐 r/java
90
121
October 26, 2024
🌐
How to do in Java
howtodoinjava.com › home › java streams › java stream to map with collectors.tomap() examples
Java Stream to Map With Collectors.toMap() Examples
March 18, 2019 - To convert a Java Stream to a Map, we call collect() with Collectors.toMap() and pass two functions, one that returns the key and one that returns the value for each stream item. The collector puts every item into a Map and returns that map.
🌐
Medium
medium.com › @AlexanderObregon › javas-collectors-tomap-method-explained-f95999d4ebe6
Java's Collectors.toMap() Method Explained
October 20, 2024 - The toMap() method from the java.util.stream.Collectors class is a powerful tool in Java that allows developers to collect stream elements into a Map.
🌐
GeeksforGeeks
geeksforgeeks.org › java › stream-map-java-examples
Stream map() in Java with examples - GeeksforGeeks
January 4, 2025 - Java Collection · Last Updated : 4 Jan, 2025 · Stream map(Function mapper) returns a stream consisting of the results of applying the given function to the elements of this stream.
🌐
Reddit
reddit.com › r/javahelp › need help with .stream().map and collectors.tomap()
r/javahelp on Reddit: Need help with .stream().map and Collectors.toMap()
November 14, 2021 -

So I have a Map <Long, Ingredient> normalMap and my method needs to first invert the keys&values and lastly return the map as Map <String, Long>

To invert the map I wrote the following code:

invertedMap = normalMap.entrySet().stream().collect(Collectors.toMap(Map.Entry::getValue, Map.Entry::getKey));

So far, so good.

Now I need to make my inverted Map return the Name of my Object as a String. Note: My Ingredient Object has a @ Override method which overrides the toString() method and basically return the getter method { this.getName(); }

So what my idea was to write the following code:

return invertedMap.entrySet().stream().collect(Collectors.toMap(Ingredient::toString, Function.identity()));

Unfortunately, this does not work. I'm googling and trying to find a solution and whenever I find something useful it creates new errors. Pls help.

Update: I managed to make it work using following code:

        Map<String, Long> ingToString = new HashMap<>();
        for (Map.Entry<Ingredient, Long> entry : invertedMap.entrySet())
        {
            Ingredient ing = entry.getKey();
            ingToString.put(entry.getKey().toString(), entry.getValue());
        }
        return ingToString;

But my question still is, what is the equivalent to this code but using .stream() ?

Top answer
1 of 3
3
So I have a Map normalMap and my method needs to first invert the keys&values and lastly return the map as Map Why not do both at the same time? return normalMap.entrySet().stream().collect(Collectors.toMap( e -> e.getValue().toString(), Map.Entry::getKey));
2 of 3
1
Please ensure that: Your code is properly formatted as code block - see the sidebar (About on mobile) for instructions You include any and all error messages in full You ask clear questions You demonstrate effort in solving your question/problem - plain posting your assignments is forbidden (and such posts will be removed) as is asking for or giving solutions. Trying to solve problems on your own is a very important skill. Also, see Learn to help yourself in the sidebar If any of the above points is not met, your post can and will be removed without further warning. Code is to be formatted as code block (old reddit: empty line before the code, each code line indented by 4 spaces, new reddit: https://imgur.com/a/fgoFFis ) or linked via an external code hoster, like pastebin.com, github gist, github, bitbucket, gitlab, etc. Please, do not use triple backticks (```) as they will only render properly on new reddit, not on old reddit. Code blocks look like this: public class HelloWorld { public static void main(String[] args) { System.out.println("Hello World!"); } } You do not need to repost unless your post has been removed by a moderator. Just use the edit function of reddit to make sure your post complies with the above. If your post has remained in violation of these rules for a prolonged period of time (at least an hour), a moderator may remove it at their discretion. In this case, they will comment with an explanation on why it has been removed, and you will be required to resubmit the entire post following the proper procedures. To potential helpers Please, do not help if any of the above points are not met, rather report the post. We are trying to improve the quality of posts here. In helping people who can't be bothered to comply with the above points, you are doing the community a disservice. I am a bot, and this action was performed automatically. Please contact the moderators of this subreddit if you have any questions or concerns.
🌐
DZone
dzone.com › coding › languages › java 8 map, filter, and collect examples
Java 8 Map, Filter, and Collect Examples - DZone
June 21, 2018 - This is the same logic we have used while solving coding problems to check if a given number is even or odd in Java. We are almost done. But, so far, we only have the Stream of even integers — not the List of even Integers and that's why we need to use them. Since we need a List, I called collect(Collectors.toList()), which will accumulate all even numbers into a List and return.
Find elsewhere
🌐
GeeksforGeeks
geeksforgeeks.org › java › how-to-convert-a-stream-into-a-map-in-java
How to convert a Stream into a Map in Java - GeeksforGeeks
July 15, 2025 - Introduced in Java 8, the Stream API is used to process collections of objects. A stream is a sequence of objects that supports various methods which can be pipelined to produce the desired result.
🌐
Medium
medium.com › geekculture › java-streams-collect-a-stream-to-map-40480b96a38
Java Streams: Collect a Stream to Map | Geek Culture
May 7, 2022 - How to Collect a stream back into a list using Collectors . toMap method. Examples with lambda functions, method reference, identity functions an functional programming.
🌐
Java Code Geeks
javacodegeeks.com › home › core java
Collectors.toMap() vs Collectors.groupingBy() in Java Streams - Java Code Geeks
June 27, 2024 - In summary, Collectors.toMap() is suitable for direct mapping of stream elements to a map, while Collectors.groupingBy() is ideal for grouping elements based on common attributes or criteria, often resulting in a map where each key maps to a ...
🌐
Stack Abuse
stackabuse.com › guide-to-java-8-collectors-tomap
Guide to Java 8 Collectors: toMap()
March 30, 2023 - The method is straightforward - ... output is the value of the final Map. The return value of the method is a Collector which collects elements into a Map, whose pair <K, V> is the result of the previously applied mapping functions. We'll start by transforming our stream of ...
🌐
Java Guides
javaguides.net › 2020 › 04 › java-8-stream-map-and-collect-example.html
Java 8 Stream - map() and collect() Example
September 14, 2020 - The Stream.map() method is used to transform one object into another by applying a function. The collect() method of Stream class can be used to accumulate elements of any Stream into a Collection.
🌐
Medium
medium.com › javarevisited › how-to-use-streams-map-filter-and-collect-methods-in-java-1e13609a318b
How to use map, filter, and collect methods in Java Stream? Example Tutorial | by javinpaul | Javarevisited | Medium
January 25, 2024 - Here is the Java program to implement whatever I have said in the above section. You can run this program in IDE or from the command line and see the result. You can also experiment with using more map() functions or more filter() calls to make the composition longer and more sophisticated. You can even play with the collect() method to collect the result in a list, set, map or any other collection.
🌐
Medium
medium.com › @AlexanderObregon › javas-collectors-mapping-method-explained-661ce6ce5bd2
Java’s Collectors.mapping() Method Explained | Medium
November 27, 2024 - The mapping() method allows us to apply a function to extract the names and collect them into lists, all within a single pipeline. import java.util.*; import java.util.stream.Collectors; class Employee { String name; String department; ...
🌐
Medium
medium.com › geekculture › java-streams-collect-to-map-of-lists-with-grouping-by-8cb309df4598
Java Streams: Collect to Map of Lists with Grouping By | Geek Culture
May 7, 2022 - How to collect a stream into a map of lists, to avoid duplicate key exception, using the Collectors . groupingBy method method reference lambda functions
🌐
DigitalOcean
digitalocean.com › community › tutorials › java-stream-collect-method-examples
Java Stream collect() Method Examples | DigitalOcean
Technical tutorials, Q&A, events — This is an inclusive place where developers can find or lend support and discover new ways to contribute to the community.
🌐
GeeksforGeeks
geeksforgeeks.org › java › collectors-tomap-method-in-java-with-examples
Collectors toMap() method in Java with Examples - GeeksforGeeks
December 26, 2025 - Example: This example demonstrates how to use Collectors.toMap() to convert a stream of key–value pairs into a Map when all keys are unique. ... import java.util.*; import java.util.stream.*; class GFG { public static void main(String[] args) { Stream<String[]> stream = Stream.of( new String[][]{ {"GFG", "GeeksForGeeks"}, {"g", "geeks"} } ); Map<String, String> map = stream.collect(Collectors.toMap(p -> p[0], p -> p[1])); System.out.println(map); } }
🌐
YouTube
youtube.com › watch
Java 8 Stream #4 - map() and collect() Example
Enjoy the videos and music you love, upload original content, and share it all with friends, family, and the world on YouTube.