What is a Map in Java?
There are many interpretations of this, but let’s simply put it this way.K | Kite, King, Korea, Knight,..., etc. |
L | Lava, Life, Light, Love, Lebanon,..., etc. |
Key | Value |
---|---|
Family ID | Family Members |
Class Name | Student IDs |
Area Name | Zip Codes |
Area Block | House Numbers |
Why do we need to iterate through a Map?
We need to traverse or iterate over a map for accessing, modifying or removing data. Let’s explore some of the options we have.What are some common ways to iterate a Map in Java?
Though there are many ways to traverse a map. However, we will focus on the most efficient and simple ways.- The ForEach Loop method
- The Iterators method
Using the Foreach Loop method
Example
import java.util.Map;
import java.util.HashMap;
public class ForEachDemo {
public static void main(String[] args) {
Map<String, String> businessDays = new HashMap<String, String>();
// store business days i-e; key/value pairs in the Map
businessDays.put("1", "Monday");
businessDays.put("2", "Tuesday");
businessDays.put("3", "Wednesday");
businessDays.put("4", "Thursday");
businessDays.put("5", "Friday");
// Iterating over the Map.entrySet() using map.forEach
for (Map.Entry<String, String> entry : businessDays.entrySet())
{
System.out.println("key = " + entry.getKey() + ", value = " + entry.getValue());
}
}
}
Output
Explanation
In this example we used the foreach loop to iterate over the map. By using the for-each loop, we get an entrySet() which provides an automated “view” of the data in the map, in the form of key-value pairs. Each entrySet contains a key and corresponding values. Where you can use all the methods of Map.Entry<key, value> as per your requirements. Here, we have only used getKey() and getValue() to display the data on the console. As an exercise, you can explore the rest of the methods to strengthen your command on this concept.Using the Iterators method
Example
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
public class MapIterator {
public static void main(String[] args) {
Map<String, String> monthsInAYear = new HashMap<String, String>();
// store business days i-e; key/value pairs in the Map
monthsInAYear.put("1", "January");
monthsInAYear.put("2", "February");
monthsInAYear.put("3", "March");
monthsInAYear.put("4", "April");
monthsInAYear.put("5", "May");
monthsInAYear.put("6", "June");
monthsInAYear.put("7", "July");
monthsInAYear.put("8", "August");
monthsInAYear.put("9", "September");
monthsInAYear.put("10", "October");
monthsInAYear.put("11", "November");
monthsInAYear.put("12", "December");
// iterate map / traverse the map using using iterator
Iterator<Map.Entry<String, String>> iterator = monthsInAYear.entrySet().iterator();
while (iterator.hasNext())
{
// check if next entry exists in the map
Map.Entry<String, String> entry = iterator.next();
System.out.println("key = " + entry.getKey() + ", value = " + entry.getValue());
}
}
}
Output
Explanation
In this example, we create explicit iterator to traverse / iterate over the map. First, you need to import the iterator class, and then get the iterator for the entrySet. Now traverse the map while keep checking the next entity that exists on the map. There you go! Your traversal is complete, just like that.Is the Foreach loop better than the iterators method?
It does not matter which method you use for the traversal of a map as long as it does the job for you. In terms of performance, both for-each loop and the iterators have the same time complexity. So none is better than the other, it depends on what you need to use and when.What is the difference between the two methods?
The for-each loop does not allow to update/modify the data in the map. On the contrary, you can easily modify data using iterators. The iterators class facilitates you by providing implementation to edit/remove the data in the map. Contrarily, if you try to edit/delete map data using the for-each loop, it will throw a ConcurrentModificationException. The reason for this is that the for-each loop implicitly creates an iterator, that is not exposed to the user. Hence, you don’t have the access to modify or delete any data.Which traversal method to use and when?
If you are not sure whether to use the for-each or the iterators to iterate your map, then you can take the following suggestions.- User the iterator if you have to modify the map.
- Use the for-each loop if you have nested loops (to avoid complexity).
Using the Stream API for Map Iteration
The Stream API, introduced in Java 8, offers a functional and concise way to iterate over a Map
. This approach is particularly useful for performing operations on the Map’s entries, keys, or values in a declarative style.
Example: Iterating Over Map Entries
import java.util.HashMap;
import java.util.Map;
public class StreamMapIteration {
public static void main(String[] args) {
Map<String, Integer> map = new HashMap<>();
map.put("Apple", 3);
map.put("Banana", 5);
map.put("Cherry", 2);
map.entrySet().stream()
.forEach(entry -> System.out.println(entry.getKey() + ": " + entry.getValue()));
}
}
This example demonstrates how to use the stream()
method to process each entry in the Map with a lambda expression.
Example: Iterating Over Keys
map.keySet().stream()
.forEach(key -> System.out.println("Key: " + key));
Example: Iterating Over Values
map.values().stream()
.forEach(value -> System.out.println("Value: " + value));
Using parallelStream() for Map Iteration
The parallelStream()
method allows you to leverage parallel processing for faster iteration, especially when dealing with large Maps. This approach splits the stream into multiple sub-streams, processing them concurrently.
Example: Parallel Processing with Map Entries
map.entrySet().parallelStream()
.forEach(entry -> System.out.println(entry.getKey() + ": " + entry.getValue()));
In this example, the parallelStream()
method processes the entries concurrently, potentially reducing iteration time for large datasets.
Note: While parallelStream()
can improve performance, it’s essential to consider thread-safety and whether the operation is CPU-bound to avoid unexpected behavior.
Combining Stream API Operations with Map Iteration
The Stream API enables complex operations like filtering, mapping, and collecting during Map iteration. This makes it a powerful tool for data transformation and aggregation.
Example: Filtering Map Entries
map.entrySet().stream()
.filter(entry -> entry.getValue() > 3)
.forEach(entry -> System.out.println(entry.getKey() + ": " + entry.getValue()));
This example filters out entries where the value is greater than 3 before processing them.
Example: Transforming Map Values
map.entrySet().stream()
.map(entry -> entry.getKey() + " has " + (entry.getValue() * 2) + " items")
.forEach(System.out::println);
Here, the map()
operation is used to transform the entries into a customized format.
Example: Collecting Results into a New Map
import java.util.stream.Collectors;
Map<String, Integer> filteredMap = map.entrySet().stream()
.filter(entry -> entry.getValue() > 3)
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
System.out.println(filteredMap);
In this example, the filtered entries are collected into a new Map using Collectors.toMap()
.
GO TO FULL VERSION