Table of Contents
In this post, we will see how to convert List to Map using Stream in java 8.
Collectors’s toMap()
can be used with stream to convert List to Map in java.
Consider a class Named Movie
which have 3 fields – id
, name
and genre
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
package org.arpit.java2blog; public class Movie { private String name; private String genre; public Movie(String name, String genre) { super(); this.name = name; this.genre = genre; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getGenre() { return genre; } public void setGenre(String genre) { this.genre = genre; } @Override public String toString() { return "Movie [name=" + name + ", genre=" + genre + "]"; } } |
Create a list of movies and convert with to map with name
as key and genre
as value.
Create a class Named ConvertListToMapMain
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
package org.arpit.java2blog; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.stream.Collectors; public class ConvertListToMapMain { public static void main(String[] args) { List<Movie> moviesList=getListOfMovies(); Map<String, String> moviesMap = moviesList.stream() .collect(Collectors.toMap((m)->m.getName(), (m)->m.getGenre())); System.out.println(moviesMap); } public static List<Movie> getListOfMovies() { List<Movie> moviesList=new ArrayList<>(); Movie m1=new Movie("3 idiots","Comedy"); Movie m2=new Movie("Interstellar","SciFi"); Movie m3=new Movie("Forest gump","Comedy"); Movie m4=new Movie("Matrix","SciFi"); Movie m5=new Movie("The Hangover","Comedy"); moviesList.add(m1); moviesList.add(m2); moviesList.add(m3); moviesList.add(m4); moviesList.add(m5); return moviesList; } } |
Output:
moviesMap
contains name as key and genre as value.
We can also use method references instead of lamda expressions.
1 2 3 4 |
Map<String, String> moviesMap = moviesList.stream() .collect(Collectors.toMap(Movie::getName, Movie::getGenre())); |
What happens in case of a duplicate key?
In case, duplicate keys are present, then it will throw java.lang.IllegalStateException
exception.
Let’s say we have two movies with name Matrix
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
public static List<Movie> getListOfMovies() { List<Movie> moviesList=new ArrayList<>(); Movie m1=new Movie("3 idiots","Comedy"); Movie m2=new Movie("Interstellar","SciFi"); Movie m3=new Movie("Forest gump","Comedy"); Movie m4=new Movie("Matrix","SciFi"); Movie m5=new Movie("Matrix","Comedy"); moviesList.add(m1); moviesList.add(m2); moviesList.add(m3); moviesList.add(m4); moviesList.add(m5); return moviesList; } |
When you run ConvertListToMapMain again, you will get below output:
Output:
at java.util.stream.Collectors.lambda$throwingMerger$0(Collectors.java:133)
at java.util.HashMap.merge(HashMap.java:1254)
at java.util.stream.Collectors.lambda$toMap$58(Collectors.java:1320)
at java.util.stream.ReduceOps$3ReducingSink.accept(ReduceOps.java:169)
at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1382)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:482)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:472)
at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:566)
at org.arpit.java2blog.ConvertListToMapMain.main(ConvertListToMapMain.java:14)
To resolve this issue, we need to pass merge BinaryOperator
function to Collectors.toMap()
.
1 2 3 4 5 6 |
Map<String, String> moviesMap = moviesList.stream() .collect(Collectors.toMap((m)->m.getName(), (m)->m.getGenre(), (oldValue,newValue) -> newValue )); |
When you run ConvertListToMapMain again, you will get below output:
Output:
What if you want specific Map such as TreeMap?
You can pass constructor method reference to Collectors.toMap()
to get specific map.
1 2 3 4 5 6 7 |
Map<String, String> moviesMap = moviesList.stream() .collect(Collectors.toMap( (m)->m.getName(), (m)->m.getGenre(), (oldValue,newValue) -> newValue ,TreeMap::new )); |
When you run ConvertListToMapMain again, you will get below output:
Output:
As you can see, we have TreeMap
which is sorted by name.
Get multiMap with Collectors.groupingBy()
In case, you want movie grouped by genre as key and name as value, then you can use Collectors.groupingBy() and Collectors.mapping as below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
package org.arpit.java2blog; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.stream.Collectors; public class ConvertListToMapMain { public static void main(String[] args) { List<Movie> moviesList=getListOfMovies(); Map<String, List<String>> moviesGenMap = moviesList.stream() .collect(Collectors.groupingBy(Movie::getGenre ,Collectors.mapping(Movie::getName, Collectors.toList()))); System.out.println(moviesGenMap); } public static List<Movie> getListOfMovies() { List<Movie> moviesList=new ArrayList<>(); Movie m1=new Movie("3 idiots","Comedy"); Movie m2=new Movie("Interstellar","SciFi"); Movie m3=new Movie("Forest gump","Comedy"); Movie m4=new Movie("Matrix","SciFi"); Movie m5=new Movie("The Hangover","Comedy"); moviesList.add(m1); moviesList.add(m2); moviesList.add(m3); moviesList.add(m4); moviesList.add(m5); return moviesList; } } |
Output:
As you can see, moviesGenMap
has genre as key and list of movies name as value.
Excercise
Given a list of Employee
objects, you need to convert list to Map with name
as key and age
as value. In case, there are duplicate keys, then you need to preserve old value.
Here is the definition of Employee class.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
package org.arpit.java2blog; public class Employee { String name; int age; public Employee(String name,int age) { super(); this.name = name; this.age=age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } } |
That’s all about Java stream List to Map
Well explained