Java Stream List to Map

Java Stream List to Map

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

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

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 moviesList=getListOfMovies();

        Map moviesMap = moviesList.stream()
                  .collect(Collectors.toMap((m)->m.getName(), (m)->m.getGenre()));
        System.out.println(moviesMap);
    }  

    public static List getListOfMovies()
    {
        List 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:

{Interstellar=SciFi, Matrix=SciFi, The Hangover=Comedy, Forest gump=Comedy, 3 idiots=Comedy}

moviesMap contains name as key and genre as value.
We can also use method references instead of lamda expressions.

Map 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

public static List getListOfMovies()
    {
        List 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:

Exception in thread “main” java.lang.IllegalStateException: Duplicate key Sci Fi
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().

Map 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:

{Matrix=Comedy, Interstellar=SciFi, Forest gump=Comedy, 3 idiots=Comedy}

What if you want specific Map such as TreeMap?

You can pass constructor method reference to Collectors.toMap() to get specific map.

Map 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:

{3 idiots=Comedy, Forest gump=Comedy, Interstellar=SciFi, Matrix=Comedy}

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:

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 moviesList=getListOfMovies();

        Map> moviesGenMap = moviesList.stream()
                  .collect(Collectors.groupingBy(Movie::getGenre
                                                ,Collectors.mapping(Movie::getName, Collectors.toList())));
        System.out.println(moviesGenMap);
    }  

    public static List getListOfMovies()
    {
        List 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:

{Comedy=[3 idiots, Forest gump, The Hangover], SciFi=[Interstellar, Matrix]}

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.

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;
    }
}
[showhide type=”question1″ more_text=”Show Answer” less_text=”Hide Answers”]
We can use Collectors.toMap() to convert list of employees to Map. As we need to preserve old values in case of duplicate key, we have used merge function as (oldValue,newValue)->oldValue

package org.arpit.java2blog;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class ExcerciseListToMap {
	
	public static void main(String[] args) {
		List eList=getListOfEmployees();
		
		Map mapNameToAge = eList.stream()
		                                .collect(Collectors.toMap(Employee::getName
		                                		                  ,Employee::getAge
		                                		                  ,(oldValue,newValue)->oldValue
		                                		));
		System.out.println(mapNameToAge);
		
	}
	private static List getListOfEmployees() {
		
		List listOfEmployees=new ArrayList<>();
		
		Employee e1=new Employee("Amit",24);
		Employee e2=new Employee("Anchit",27);
		Employee e3=new Employee("Vaibhav",32);
		Employee e4=new Employee("Amit",22);
		
		listOfEmployees.add(e1);
		listOfEmployees.add(e2);
		listOfEmployees.add(e3);
		listOfEmployees.add(e4);
		
		return listOfEmployees;
	}

}

Output:

{Amit=24, Vaibhav=32, Anchit=27}

[/showhide]

That’s all about Java stream List to Map

[social_share share_on="facebook,twitter,linkedin,whatsapp"][post_navigator in_same_term="true"]

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *

Subscribe to our newletter

Get quality tutorials to your inbox. Subscribe now.