Java8
HashMap
Stream
Map-Reduce
Collector

Java8 HashMap<X, Y> to HashMap<X, Z> using Stream / Map-Reduce / Collector

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

Java 8 introduced a significant upgrade to the Java programming language and its core libraries, particularly Java Collections and Streams. One of the most powerful features introduced in Java 8 is the Stream API, which allows for functional-style operations on collections of objects. In this discussion, we will delve into how to effectively transform a HashMap<X, Y> into a HashMap<X, Z> using Java 8 Streams, alongside using map-reduce operations and collectors.

Understanding HashMap and Streams

Before we proceed, it's essential to understand what a HashMap does and what Java 8 Streams are. A HashMap is a part of Java's collection framework that stores items in key-value pairs. Keys are unique, and each key maps to exactly one value. The Stream API, meanwhile, allows for declarative operations on collections of objects, such as sequential or parallel map-reduce transformations.

Transformation of HashMap<X, Y> to HashMap<X, Z>

To demonstrate how to transform HashMap<X, Y> to HashMap<X, Z>, let’s suppose we have a HashMap where each key is a student's ID (Type X), and each value is their name (Type Y). We want to transform this to a new HashMap where each key is the student's ID (still Type X), but each value is now the length of their name (Type Z, which in this case would be Integer).

Step-by-Step Transformation Using Streams

Assuming we have:

java
1HashMap<Integer, String> idToNameMap = new HashMap<>();
2idToNameMap.put(1, "Alice");
3idToNameMap.put(2, "Bob");
4idToNameMap.put(3, "Christina");
5idToNameMap.put(4, "David");

We want to transform this map to HashMap<Integer, Integer> where the values are the lengths of the names.

Here’s how we can achieve this using Streams in Java 8:

java
1HashMap<Integer, Integer> idToNameLengthMap = idToNameMap.entrySet()
2    .stream()
3    .collect(Collectors.toMap(
4        Map.Entry::getKey,
5        entry -> entry.getValue().length(),
6        (oldValue, newValue) -> oldValue, // to handle collision
7        HashMap::new
8    ));

Explanations:

  1. idToNameMap.entrySet().stream() - Convert the entry set of the map into a stream.
  2. .collect(Collectors.toMap(...)) - Collects the elements of the stream into a new HashMap.
  3. Map.Entry::getKey - Uses the keys from the original map as keys for the new map.
  4. entry -> entry.getValue().length() - Transforms each value (name) into its length.
  5. (oldValue, newValue) -> oldValue - A merge function to handle key collisions, which simply keeps the old value (not necessary in this context since keys are unique).
  6. HashMap::new - Creates a new empty HashMap.

Table Summary

FeatureDescriptionUsage in Transformation
Stream APIEnables functional-style operations on streams of elements.Used to convert collections into stream for processing.
map()Transforms the stream's elements from one form to another.Not explicitly used here, but implied in Collectors.toMap() for transformation.
Collectors.toMap()Collects elements into a Map based on provided functions.Used to collect transformed elements into a new HashMap.

Additional Considerations and Optimization

While our primary transformation is straightforward, handling more complex transformations or performance optimizations might require additional considerations:

  • Parallel Streams: For large datasets, consider using parallel streams (idToNameMap.entrySet().parallelStream()) to speed up processing.
  • Custom Collector Implementations: For specialized reduction operations that aren't covered by standard collectors.

Conclusion

Transforming a HashMap<X, Y> to a HashMap<X, Z> using Java 8's Stream API is a powerful and elegant way to process and mutate collections. By leveraging the operations provided by Streams, one can write clean, efficient, and expressive code that smoothly transforms and processes large data structures.


Related reading
Course
Intermediate
27 lessons
15 hours
DSA Fundamentals

Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

All Rights Reserved.