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
nullkeys 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 containnullkeys or values. If the stream containsnull, aNullPointerExceptionis 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
Fruitobjects 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
NullPointerExceptionif the stream containsnullkeys or values.
By using Collectors.toUnmodifiableMap(), you can create safe, immutable maps in your Java applications, making your code more robust and reliable.