Core Java

Iterate over a Guava Multimap

A Multimap is a collection that maps keys to values, where each key may be associated with multiple values. Let us delve into understanding how to iterate over a Guava Multimap.

1. Introduction

The Guava library provides a Multimap interface that lets us map a single key to multiple values. This is helpful when you want a data structure similar to a Map, but with the flexibility to handle multiple values per key.

1.1 Pros of Multimap

  • Eliminates the need for Map<Key, List<Value>> constructs, making code cleaner.
  • Provides various implementations for different use cases, like sorted or unordered storage.
  • Built-in methods for key-value pair iteration make it easy to manage and retrieve values.

1.2 Dependency

To use Multimap, you need to add the Guava library to your project.

If you’re using Maven, add the following dependency:

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>latest_jar_version</version>
</dependency>

If you’re using Gradle, add:

implementation 'com.google.guava:guava:latest_jar_version'

2. Multimap Implementation

Guava provides different Multimap implementations, such as:

  • ArrayListMultimap – Allows duplicate key-value pairs.
  • HashMultimap – Does not allow duplicate key-value pairs.
  • LinkedListMultimap – Maintains insertion order.
  • TreeMultimap – Stores keys and values in sorted order.

Here’s an example that demonstrates the behavior of each type of Multimap implementation:

import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.LinkedListMultimap;
import com.google.common.collect.TreeMultimap;
import com.google.common.collect.Multimap;

public class MultimapExample {
    public static void main(String[] args) {
        // ArrayListMultimap - Allows duplicate values for the same key
        Multimap<String, String> arrayListMultimap = ArrayListMultimap.create();
        arrayListMultimap.put("fruit", "apple");
        arrayListMultimap.put("fruit", "apple"); // Duplicate allowed
        arrayListMultimap.put("fruit", "banana");
        System.out.println("ArrayListMultimap: " + arrayListMultimap);

        // HashMultimap - Does not allow duplicate key-value pairs
        Multimap<String, String> hashMultimap = HashMultimap.create();
        hashMultimap.put("fruit", "apple");
        hashMultimap.put("fruit", "apple"); // Duplicate ignored
        hashMultimap.put("fruit", "banana");
        System.out.println("HashMultimap: " + hashMultimap);

        // LinkedListMultimap - Maintains insertion order
        Multimap<String, String> linkedListMultimap = LinkedListMultimap.create();
        linkedListMultimap.put("fruit", "banana");
        linkedListMultimap.put("fruit", "apple");
        linkedListMultimap.put("fruit", "orange");
        System.out.println("LinkedListMultimap: " + linkedListMultimap);

        // TreeMultimap - Stores keys and values in sorted order
        Multimap<String, String> treeMultimap = TreeMultimap.create();
        treeMultimap.put("fruit", "banana");
        treeMultimap.put("fruit", "apple");
        treeMultimap.put("fruit", "orange");
        System.out.println("TreeMultimap: " + treeMultimap);
    }
}

2.1 Code Explanation and Output

In the main method, we create and manipulate each type of Multimap, showcasing their unique behaviors:

  • ArrayListMultimap: The ArrayListMultimap allows duplicate values for the same key. In this example, the key “fruit” is mapped to two “apple” values, which are allowed since duplicates are supported. The resulting output shows three values for the “fruit” key: two “apple” entries and one “banana” entry.
  • HashMultimap: The HashMultimap does not allow duplicate key-value pairs. When we try to put the same key-value pair (“fruit” -> “apple”) again, it is ignored. As a result, only one “apple” value is associated with the “fruit” key, and the output shows just “apple” and “banana” for the “fruit” key.
  • LinkedListMultimap: The LinkedListMultimap maintains the order of insertion. In this case, the keys and values are inserted in the order “banana”, “apple”, and “orange”. As a result, the output reflects this order, with “fruit” mapped to “banana”, “apple”, and “orange”.
  • TreeMultimap: The TreeMultimap stores both keys and values in sorted order. When we add the values “banana”, “apple”, and “orange” for the “fruit” key, the TreeMultimap sorts them alphabetically. Thus, the output shows “apple”, “banana”, and “orange” in sorted order.

The code demonstrates the practical use of these different Multimap types to handle multiple values for a single key, with different behaviors depending on the implementation.

The output for each Multimap type is printed to the console:

ArrayListMultimap: {fruit=[apple, apple, banana]}

HashMultimap: {fruit=[apple, banana]}

LinkedListMultimap: {fruit=[banana, apple, orange]}

TreeMultimap: {fruit=[apple, banana, orange]}

3. Iterate Over a Multimap

You can iterate through each key-value pair using multimap.entries(). Alternatively, if you only need to iterate over the keys, use multimap.keySet() and retrieve the associated values for each key. For iterating solely over values, use multimap.values() to access all values independently in the Multimap. Let’s explore this with an example:

import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import java.util.Map;

public class MultimapIterationExample {
    public static void main(String[] args) {
        // Create and populate an ArrayListMultimap
        Multimap<String, String> multimap = ArrayListMultimap.create();
        multimap.put("fruit", "apple");
        multimap.put("fruit", "banana");
        multimap.put("vegetable", "carrot");
        multimap.put("vegetable", "broccoli");

        // Iterate over all key-value pairs using entries()
        System.out.println("Iterating over all key-value pairs:");
        for (Map.Entry<String, String> entry : multimap.entries()) {
            System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue());
        }

        // Iterate over each key and its associated values using keySet()
        System.out.println("\nIterating over each key and associated values:");
        for (String key : multimap.keySet()) {
            System.out.print("Key: " + key + ", Values: ");
            for (String value : multimap.get(key)) {
                System.out.print(value + " ");
            }
            System.out.println();
        }

        // Iterate over all values only using values()
        System.out.println("\nIterating over all values:");
        for (String value : multimap.values()) {
            System.out.println("Value: " + value);
        }
    }
}

3.1 Code Explanation and Output

  • Using entries(): The entries() method provides a flattened view of all key-value pairs as individual entries. In the first loop, we use entries() to iterate over each key-value pair in the multimap. Each entry in the loop is a Map.Entry<String, String> object, which allows us to access both the key and value of each pair directly.
  • Using keySet() and get(key): The keySet() method returns a set of all unique keys in the multimap. For each key, we retrieve its associated values by calling multimap.get(key). This returns a collection of values associated with that specific key. In the second loop, we print each key followed by all of its associated values.
  • Using values(): The values() method provides a collection of all values in the multimap, without keys. We use this method to iterate over each value individually.

The output of the code is printed to the console:

Iterating over all key-value pairs:
Key: fruit, Value: apple
Key: fruit, Value: banana
Key: vegetable, Value: carrot
Key: vegetable, Value: broccoli

Iterating over each key and associated values:
Key: fruit, Values: apple banana 
Key: vegetable, Values: carrot broccoli 

Iterating over all values:
Value: apple
Value: banana
Value: carrot
Value: broccoli

4. Compared to the Standard Map

Unlike a standard Map, where each key maps to a single value, Multimap allows each key to map to multiple values. Here’s how they differ:

  • Map<String, List<String>> requires manual handling to add multiple values per key, while Multimap handles this automatically.
  • Multimap has better readability and more flexibility for many-to-one or many-to-many mappings.

5. Conclusion

The Guava Multimap is a powerful tool for managing key-value relationships where each key may have multiple values. By understanding how to implement and iterate over a Multimap, you can simplify complex mappings and improve code readability.

Yatin Batra

An experience full-stack engineer well versed with Core Java, Spring/Springboot, MVC, Security, AOP, Frontend (Angular & React), and cloud technologies (such as AWS, GCP, Jenkins, Docker, K8).
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Back to top button