This post shows how to convert a stream of objects to Map entries in Java using Collectors.toMap methods. Furthermore, we’ll handle duplicate IDs for May keys. Most importantly. We need Java 8 for this post because the Stream API is only available in this version.
The Class for Our Map Object
Consider the following codes. We will use the class to create a list of objects and convert them into Map entries. Since Map entries are key-value pairs, we need to use id as key and an instance of NewPersonBean as value.
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 41 42 43 44 45 46 47 | package com.example.demo1; import java.util.ArrayList; import java.util.List; class NewPersonBean { private Integer id; private String name; private List<NewPersonBean> duplicates = new ArrayList<>(); public NewPersonBean(Integer id, String name) { super(); this.id = id; this.name = name; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public List<NewPersonBean> getDuplicates() { return duplicates; } public void setDuplicates(List<NewPersonBean> duplicates) { this.duplicates = duplicates; } @Override public String toString() { String str = duplicates.isEmpty() ? "" : "\n*** Other persons with same ID: " + duplicates.toString() + " ***\n"; return "NewPersonBean [id=" + id + ", name=" + name + ", " + str + "]"; } } |
Notice that we have a List object within the class. We will use the list to gather duplicate (handle collisions) entries from Java Stream values.
Convert Java Stream Values to Map Entries
Here the example codes that show how we convert Java Stream values to Map entries.
Example 1 – Using Two Parameters
The first example uses Collectors.toMap method with two parameters.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | import java.util.Map; import java.util.stream.Collectors; import java.util.stream.Stream; public class StreamToMapDemo { public static void main(String[] args) { Stream<NewPersonBean> stream = Stream.of( new NewPersonBean(1, "James"), new NewPersonBean(2, "Cindy"), new NewPersonBean(3, "John"), new NewPersonBean(4, "Kits")); // Alternatively, we could use method reference // Map<Integer, NewPersonBean> map1 = stream.collect(Collectors.toMap( // NewPersonBean::getId, bean -> bean)); Map<Integer, NewPersonBean> map1 = stream.collect(Collectors.toMap( bean->bean.getId(), bean -> bean)); System.out.println(map1); } } |
The codes generate the following output.
1 | {1=NewPersonBean [id=1, name=James, ], 2=NewPersonBean [id=2, name=Cindy, ], 3=NewPersonBean [id=3, name=John, ], 4=NewPersonBean [id=4, name=Kits, ]} |
Example 2 – Handle Collisions
This example uses a Collectors.toMap method with three parameters. Therefore, we need two NewPersonBean objects with identical ids to trigger the 3rd parameter to “handle collisions.”
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 | import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import java.util.stream.Stream; public class StreamToMapDemo2 { public static void main(String[] args) { Stream<NewPersonBean> stream = Stream.of( new NewPersonBean(1, "James"), new NewPersonBean(2, "Cindy"), // Duplicates here! new NewPersonBean(3, "John"), new NewPersonBean(3, "Sandy"), new NewPersonBean(4, "Kits")); // We add the object with the same Ids to a list to display later Map<Integer, NewPersonBean> map1 = stream.collect(Collectors.toMap( bean->bean.getId(), bean -> bean, (s,a) -> { s.getDuplicates().add(a); return s; }) ); System.out.println(map1); } } |
The codes generate the following output.
1 2 3 | {1=NewPersonBean [id=1, name=James, ], 2=NewPersonBean [id=2, name=Cindy, ], 3=NewPersonBean [id=3, name=John, *** Other persons with same ID: [NewPersonBean [id=3, name=Sandy, ]] *** ], 4=NewPersonBean [id=4, name=Kits, ]} |
Example 3 – Handle Collision And Accumulate Duplicates
The following example uses Collectors.toMap method with four parameters. The difference between this example and the previous example is we accumulate the duplicates we find during the conversion.
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 | import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import java.util.stream.Stream; public class StreamToMapDemo3 { public static void main(String[] args) { Stream<NewPersonBean> stream = Stream.of( new NewPersonBean(1, "James"), new NewPersonBean(2, "Cindy"), // Duplicates here! new NewPersonBean(3, "John"), new NewPersonBean(3, "Sandy"), new NewPersonBean(4, "Kits")); Map<Integer, NewPersonBean> map1 = stream.collect(Collectors.toMap( bean->bean.getId(), bean -> bean, (s,a) -> { s.getDuplicates().add(a); return s; }, () -> { Map<Integer, NewPersonBean> map = new HashMap<>(); map.put(-1, new NewPersonBean(-1, null)); return map; }) ); System.out.println(map1); } } |
The sample codes output the following result.
1 2 3 | {-1=NewPersonBean [id=-1, name=null, ], 1=NewPersonBean [id=1, name=James, ], 2=NewPersonBean [id=2, name=Cindy, ], 3=NewPersonBean [id=3, name=John, *** Other persons with same ID: [NewPersonBean [id=3, name=Sandy, ]] *** ], 4=NewPersonBean [id=4, name=Kits, ]} |