Introduction
Java 10 introduced the Collectors.toUnmodifiableMap()
method, which is used to collect elements from a stream into an unmodifiable map. This method is part of the Java Stream API and provides a way to create read-only maps directly from streams. Once created, the resulting map cannot be modified, ensuring data integrity and immutability.
Key Points:
- Immutable Map:
Collectors.toUnmodifiableMap()
creates a map that cannot be changed. - Stream API: Used with streams to collect elements into an unmodifiable map.
- Read-Only: Any attempt to modify the resulting map will throw an
UnsupportedOperationException
. - Null Safety: If the stream contains
null
keys or values, the collector will throw aNullPointerException
.
How to Use Collectors.toUnmodifiableMap()
The Collectors.toUnmodifiableMap()
method is used as a terminal operation in a stream pipeline to collect elements into an unmodifiable map.
Syntax:
Map<K, V> unmodifiableMap = stream.collect(Collectors.toUnmodifiableMap(keyMapper, valueMapper));
- stream: A stream of elements to be collected.
- keyMapper: A function that extracts keys from the stream elements.
- valueMapper: A function that extracts values from the stream elements.
- unmodifiableMap: The resulting read-only map.
Example of Using Collectors.toUnmodifiableMap()
Basic Example
Here’s a simple example demonstrating the use of Collectors.toUnmodifiableMap()
with Indian cities and their populations:
import java.util.Map; import java.util.stream.Collectors; import java.util.stream.Stream; public class UnmodifiableMapExample { public static void main(String[] args) { // Create a stream of cities and their populations Stream<String[]> cityStream = Stream.of( new String[]{"Mumbai", "20 million"}, new String[]{"Delhi", "18 million"}, new String[]{"Bengaluru", "10 million"}, new String[]{"Chennai", "8 million"} ); // Collect the stream elements into an unmodifiable map Map<String, String> cityMap = cityStream.collect( Collectors.toUnmodifiableMap( city -> city[0], // Key Mapper: City Name city -> city[1] // Value Mapper: Population ) ); System.out.println("Unmodifiable City Map: " + cityMap); // Attempt to modify the unmodifiable map try { cityMap.put("Hyderabad", "7 million"); // This will throw UnsupportedOperationException } catch (UnsupportedOperationException e) { System.out.println("Cannot modify cityMap: " + e.getMessage()); } } }
Output:
Unmodifiable City Map: {Mumbai=20 million, Delhi=18 million, Bengaluru=10 million, Chennai=8 million} Cannot modify cityMap: null
Explanation:
- Immutable Map: The
Collectors.toUnmodifiableMap()
method creates a map that cannot be modified, ensuring the map’s content is protected. - Error on Modification: Any attempt to modify the resulting map, such as adding or removing entries, will result in an
UnsupportedOperationException
.
Null Safety
The Collectors.toUnmodifiableMap()
method does not allow null
keys or values in the stream. If the stream contains null
, a NullPointerException
is thrown.
Example:
import java.util.Map; import java.util.stream.Collectors; import java.util.stream.Stream; public class NullSafetyExample { public static void main(String[] args) { // Create a stream with a null key Stream<String[]> cityStream = Stream.of( new String[]{"Mumbai", "20 million"}, new String[]{null, "18 million"}, // Null key new String[]{"Bengaluru", "10 million"} ); try { // Attempt to collect the stream into an unmodifiable map Map<String, String> cityMap = cityStream.collect( Collectors.toUnmodifiableMap( city -> city[0], // Key Mapper: City Name city -> city[1] // Value Mapper: Population ) ); } catch (NullPointerException e) { System.out.println("Stream contains null keys: " + e.getMessage()); } } }
Output:
Stream contains null keys: null
Explanation:
- No Null Keys or Values: The
Collectors.toUnmodifiableMap()
method ensures that the resulting map does not containnull
keys or values. If the stream containsnull
, aNullPointerException
is thrown.
Real-World Example
Using Collectors.toUnmodifiableMap()
is beneficial when you want to create a map from a stream and ensure that the map remains unchanged.
Example with Fruit Prices:
import java.util.List; import java.util.Map; import java.util.stream.Collectors; public class FruitPriceExample { public static void main(String[] args) { // Create a list of fruits and their prices List<Fruit> fruits = List.of( new Fruit("Mango", 50), new Fruit("Banana", 20), new Fruit("Apple", 70), new Fruit("Orange", 60) ); // Collect the list into an unmodifiable map with fruit names as keys and prices as values Map<String, Integer> fruitPriceMap = fruits.stream() .collect(Collectors.toUnmodifiableMap( Fruit::getName, // Key Mapper: Fruit Name Fruit::getPrice // Value Mapper: Fruit Price )); System.out.println("Unmodifiable Fruit Price Map: " + fruitPriceMap); // Attempt to modify the unmodifiable map try { fruitPriceMap.put("Grapes", 80); // This will throw UnsupportedOperationException } catch (UnsupportedOperationException e) { System.out.println("Cannot modify fruitPriceMap: " + e.getMessage()); } } } class Fruit { private final String name; private final int price; public Fruit(String name, int price) { this.name = name; this.price = price; } public String getName() { return name; } public int getPrice() { return price; } }
Output:
Unmodifiable Fruit Price Map: {Mango=50, Banana=20, Apple=70, Orange=60} Cannot modify fruitPriceMap: null
Explanation:
- Stream Processing: The example collects a list of
Fruit
objects into an unmodifiable map usingCollectors.toUnmodifiableMap()
. - Immutable Map: The resulting map is immutable, ensuring that the map remains unchanged.
- Error on Modification: Any attempt to add an entry to the map results in an
UnsupportedOperationException
.
Conclusion
The Collectors.toUnmodifiableMap()
method in Java 10 provides a simple way to create immutable maps from streams. This feature is particularly useful when you want to ensure that a map created from a stream remains read-only, enhancing the safety and reliability of your code.
Summary:
- Immutable Map: Creates a map that cannot be modified.
- Stream API: Collects elements from streams into an unmodifiable map.
- Read-Only: The resulting map is read-only, preventing any modifications.
- Null Safety: The collector will throw a
NullPointerException
if the stream containsnull
keys or values.
By using Collectors.toUnmodifiableMap()
, you can create safe, immutable maps in your Java applications, making your code more robust and reliable.