CodeGym /Java Blog /Stream API /Convert Stream to a Map in Java Heading
Author
Volodymyr Portianko
Java Engineer at Playtika

Convert Stream to a Map in Java Heading

Published in the Stream API group
Java provides powerful tools for working with collections and data streams. One is Stream, which allows for efficient data processing and transformation. The Stream API offers various operations to work with data, such as filtering, sorting, aggregation, transformation, and so on. Streams in Java can make data processing more convenient and efficient, especially for large datasets. In this article, we are going to talk about converting stream to a map in Java. Convert Stream to a Map in Java Heading - 1

Converting Stream to Map

Sometimes it could be helpful to convert a Stream into a Map, where the elements of the Stream become the keys, and the results of operations on the elements become the values. Converting a Stream to a Map can be beneficial when we have a stream of data, and we want to group them by a certain key and perform operations on those groups of data. Here is an example:

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

   public class StreamToMapEx1 {
       public static void main(String[] args) {
           // List of friends with their names
           List<String> friends = Arrays.asList("Johnny", "Ivy", "Rick");

           // convert our list into Stream
           Stream<String> friendsStream = friends.stream();

           // Convert Stream into Map, where the key is the friend's name, and the value is name's length
           Map<String, Integer> friendsMap = friendsStream.collect(Collectors.toMap(
                   friend -> friend,             // the key is friend's name
                   friend -> friend.length()     // value is the name's length
           ));

           // Printing out our converted Map
           System.out.println("Map with friends names : " + friendsMap);
       }
   }
The output of the program:
Map with friends names : {Johnny=6, Rick=4, Ivy=3}
What did we do here? First we create a list of friends with names "Johnny", "Ivy," and "Rick”, then we convert the list of friends into a Stream. Next we are using the collect method to transform the Stream into a Map. We specify functions to create keys and values in the Map. At last, we print out the resulting Map which contains the lengths of friends' names.

Collectors class for collecting Stream

In the example above we used the Collectors class. What's a collector? Collectors is a class in Java from the java.util.stream package. It provides static methods for aggregating elements of streams into various data structures like lists, sets, maps, etc. In the context of converting a Stream to a Map using the Collectors.toMap() method, Collectors offers methods to create collector that performs operations on stream elements and produces results in the form of a Map. The Collectors.toMap() method takes functions to extract keys and values from stream elements, along with additional parameters for controlling the Map creation (e.g., handling key collisions). Convert Stream to a Map in Java Heading - 2

More examples using Collectors.toMap()

Let’s have a look at the toMap(Function keyMapper, Function valueMapper) method. It transforms Stream elements into a Map using the provided functions to compute keys and values. If there are duplicate keys, an exception will be thrown. Here's the method's signature:

static <T, K, U> Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> value
In the example below, the Collectors.toMap() method takes a function to extract keys (the words themselves) and a function to extract values (the length of the word) from the stream. The result will be a map where words are keys, and their lengths are values.

import java.util.*;
import java.util.stream.Collectors;

class Student {
    private String name;
    private int age;

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }
}

public class Main {
    public static void main(String[] args) {
        List<Student> students = Arrays.asList(
            new Student("Johnny", 22),
            new Student("Ivy", 20),
            new Student("Rick", 21)
        );

        Map<String, Integer> studentAgeMap = students.stream()
            .collect(Collectors.toMap(
                Student::getName, // Key: Student's name
                Student::getAge   // Value: Student's age
            ));

        System.out.println(studentAgeMap);
    }
}
The output is:
{Johnny=22, Rick=21, Ivy=20}
There's another overloaded version of the toMap() method: toMap(Function keyMapper, Function valueMapper, BinaryOperator mergeFunction). This one also converts elements from the Stream into a Map, but in case of duplicate keys, it allows you to specify how to merge values using the provided mergeFunction. The method signature:

static <T, K, U> Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper, BinaryOperator<U> mergeFunction)
Here's an example code handling key conflicts:

import java.util.*;
import java.util.stream.Collectors;

class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }
}

public class Main {
    public static void main(String[] args) {
        List<Person> people = Arrays.asList(
            new Person("Johnny", 22),
            new Person("Ivy", 20),
            new Person("Rick", 21),
            new Person("Johnny", 25) // Duplicate name
        );

        // Convert the stream of people into a Map, handling duplicate keys by keeping the first value
        Map<String, Integer> personAgeMap = people.stream()
            .collect(Collectors.toMap(
                Person::getName,   // Key: Person's name
                Person::getAge,    // Value: Person's age
                (existingValue, newValue) -> existingValue // Merge function for duplicate keys
            ));

        System.out.println(personAgeMap);
    }
}

Conclusion

As you can see, converting a Stream into a Map is an effective operation that can be useful for grouping and aggregating data. Java provides a rich set of tools for working with data streams, making data processing more efficient and convenient.
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION