Nugget Friday - Did You Know This About HashMaps?

Photo of Luqman Saeed by Luqman Saeed

It’s Friday and we kick off the maiden edition of Nugget Friday. So, what is it? Nugget Friday is going to be a series of short blog posts that focus on hidden nuggets in the various JDK releases since Java 9. In this maiden edition, we look at a very obscure static method on the HashMap class introduced in Java 19.

The Problem

You already know you can initialise a map with a predefined size, right? For example:

Map<String, Rectangle> shapes = new HashMap<>(100);

You probably expect to be able to insert up to 100 elements into the map, right? On the surface, yes. But behind the scenes, the HashMap has a load factor of 0.75 (default value). What is a load factor? Working on the hashing principle, a HashMap dynamically resizes its buckets when its set capacity reaches 75%. This happens independently on whether you explicit set the capacity, like 100 in our example, or not - with the size being 16 by default. 

So, for our shapes map, when we insert the 75th element, which is 75% of 100, the HashMap will resize to double the capacity. In this example, this means 200. According to the JavaDoc of HashMap.java, “when the number of entries in the hash table exceeds the product of the load factor and the current capacity, the hash table is rehashed (that is, internal data structures are rebuilt) so that the hash table has approximately twice the number of buckets.”

For large tables, this could get expensive. The JavaDoc further recommends that “if many mappings are to be stored in a HashMap instance, creating it with a sufficiently large capacity will allow the mappings to be stored more efficiently than letting it perform automatic rehashing as needed to grow the table.”

The Solution

For our shapes map, assuming we know ahead of time that we will be storing exactly 100 elements, we can size our initial map to as follows:

Map<String, Rectangle> shapes = new HashMap<>((int) Math.ceil(100 / (double) 0.75));

This should give us an initial capacity of about 133. This way, we get to store our 100 elements in one shot without the map needing to resize. So, instead of ending up with a map with 200 elements of which we use 100, we end up with a map with 133 elements of which we use 100.

Starting with Java 19 however, instead of fiddling with the maths like we did above, you can use the static method:

Map<String, Rectangle> shapes = HashMap.newHashMap(100);

The JavaDoc for this method states that it “creates a new, empty HashMap suitable for the expected number of mappings. The returned map uses the default load factor of 0.75, and its initial capacity is generally large enough so that the expected number of mappings can be added without resizing the map.”

So there you have it! This method creates behind the scene a map that is large enough to accommodate your passed mappings value using the load factor without needing to resize the map. Neat huh? Now, when you need to create a HashMap with a predetermined size, you know which method to use!

That’s it for today. See you next Friday for another nugget. Happy Coding!

 

Related Posts

Comments