Iterating Java Map Entries
3 CommentsLast Updated on June 16, 2019 by Simanta
The majority of the time when you’re working with Maps in Java, you’ll be accessing the map values via the key. There are times you need to walk the map like a list. There’s a number of ways to do this in Java, which have grown over time as the language has evolved.
Let’s take a closer look at walking over Map entries in Java using JUnit. For the series of examples below, I’m going to prepare a map for each test like this:
Map<Integer, String> map; @Before public void setup(){ map = new HashMap<>(); map.put(1, "Java"); map.put(2, "Groovy"); map.put(3, "Scala"); map.put(4, "Clojure"); map.put(5, "jRuby"); }
This is a simple HashMap
in Java. I’m using generics to say the Map key is an integer, and the Map value is a String. For this example, I’m creating a map with some of the various JVM languages.
Using an Iterator over Map Entries
If you’re still stuck using Java 1.4, you might use an Iterator to walk the Map entries. But hopefully, you’re not still on Java 1.4! But there is plenty of legacy code out there still doing this.
Here is an example of using an Iterator over a map. I’m tossing in the use of Generics, so this code snippet is not Java 1.4 compliant. I’m also using the older style while loop.
@Test public void testMapWithIterator() throws Exception { List jvmLangs = new ArrayList<>(); Iterator iterator = map.entrySet().iterator(); while (iterator.hasNext()){ Map.Entry<Integer, String> entry = (Map.Entry<Integer, String>) iterator.next(); jvmLangs.add(entry.getValue()); } assert jvmLangs.size() == 5; }
You can see is using this technique, I need to do a cast:
(Map.Entry<Integer, String>) iterator.next();
I cringe a little every time I need to do a hard cast like this. It’s generally a code smell.
Using For Each over Map Entries
Java 1.5 gave us for each loops. A much nicer syntax for doing loop operations. Here is an example of using a for each loop over Map entries.
@Test public void testMapIteration(){ List jvmLangs = new ArrayList<>(); for (Map.Entry<Integer, String> entry : map.entrySet()){ jvmLangs.add(entry.getValue()); } assert jvmLangs.size() == 5; }
You can see the code is a little cleaner now. Also gone now is the cast, so this code smells better!
Using Java 8’s forEach over Map Entries
While the Java 7 release was rather boring for developers, Java 8 has brought us some really nice features to work with. We have a new forEach
statement we can use in conjunction with lambdas. Here is an example of using Java 8 lambdas to iterate over Map entries.
@Test public void testMapIteration() { List langs = new ArrayList<>(); map.forEach((k, v) -> langs.add(v)); assert langs.size() == 5; }
You can see Java 8 really allows us to clean up the code. No casts here. You can also see we’re skipping over explicitly dealing with the Map.Entry
object in the lambda. Even though we’re taking a shortcut here, we still have the type safety of Java.
Conclusion
I given you 3 different ways of walking over a list of map entries in Java. In my examples here you can see how the code has become cleaner as the Java programming language has evolved over the years.
Jason Carps
To make your java 1.7 and lower versions a bit better, maybe use map.keySet() instead of map.entrySet()?
aledesc
i think there’s no point iterating on a map, maps are intended for O(1) access via its key, if you need a set use a Set, List, etc…
jt
It’s actually a rather common task to walk over the entries in a map. Lots of use cases for this.