Java Collectors toUnmodifiableMap() Method

The toUnmodifiableMap() method in Java, part of the java.util.stream.Collectors class, is used to collect elements of a stream into an unmodifiable Map. This method is useful when you need to create a map that should not be modified after its creation.

Table of Contents

  1. Introduction
  2. toUnmodifiableMap() Method Syntax
  3. Understanding toUnmodifiableMap()
  4. Examples
    • Basic Usage
    • Using toUnmodifiableMap() with Custom Objects
    • Handling Duplicate Keys with Merge Function
  5. Real-World Use Case
  6. Conclusion

Introduction

The toUnmodifiableMap() method returns a Collector that accumulates the input elements into an unmodifiable Map whose keys and values are the result of applying a key mapping and value mapping function, respectively. There are multiple overloaded versions of this method to provide flexibility in how the map is constructed.

toUnmodifiableMap() Method Syntax

There are three overloaded versions of the toUnmodifiableMap() method:

  1. Basic toUnmodifiableMap() method with key and value mappers:
public static <T, K, U> Collector<T, ?, Map<K, U>> toUnmodifiableMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper)
  1. toUnmodifiableMap() method with key and value mappers and a merge function:
public static <T, K, U> Collector<T, ?, Map<K, U>> toUnmodifiableMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper, BinaryOperator<U> mergeFunction)
  1. toUnmodifiableMap() method with key and value mappers, a merge function, and a map supplier:
public static <T, K, U, M extends Map<K, U>> Collector<T, ?, M> toUnmodifiableMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper, BinaryOperator<U> mergeFunction, Supplier<M> mapSupplier)

Parameters:

  • keyMapper: A function that maps the input elements to keys.
  • valueMapper: A function that maps the input elements to values.
  • mergeFunction (optional): A binary operator used to resolve collisions between values associated with the same key.
  • mapSupplier (optional): A supplier providing a new empty Map into which the results will be inserted.

Returns:

  • A Collector that accumulates the input elements into an unmodifiable Map.

Throws:

  • This method may throw IllegalStateException if duplicate keys are encountered and no merge function is provided.

Understanding toUnmodifiableMap()

The toUnmodifiableMap() method allows you to collect the elements of a stream into an unmodifiable map. This is useful in scenarios where you need to create a map that should not be modified after its creation, ensuring immutability.

Examples

Basic Usage

To demonstrate the basic usage of toUnmodifiableMap(), we will create a stream of strings and collect them into an unmodifiable Map with the string as the key and its length as the value.

Example

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class ToUnmodifiableMapExample {
    public static void main(String[] args) {
        List<String> words = Arrays.asList("apple", "banana", "cherry", "date");

        // Collect the words into an unmodifiable Map with the word as the key and its length as the value
        Map<String, Integer> wordLengthMap = words.stream()
                                                  .collect(Collectors.toUnmodifiableMap(
                                                      word -> word,
                                                      String::length
                                                  ));

        System.out.println("Word Length Map: " + wordLengthMap);

        // Attempting to modify the map will result in an UnsupportedOperationException
        // wordLengthMap.put("elderberry", 10); // Uncommenting this line will throw an exception
    }
}

Output:

Word Length Map: {cherry=6, date=4, banana=6, apple=5}

Using toUnmodifiableMap() with Custom Objects

This example shows how to use toUnmodifiableMap() with a stream of custom objects to collect them into an unmodifiable map.

Example

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class ToUnmodifiableMapCustomObjectExample {
    static class Product {
        String name;
        double price;

        Product(String name, double price) {
            this.name = name;
            this.price = price;
        }

        String getName() {
            return name;
        }

        double getPrice() {
            return price;
        }
    }

    public static void main(String[] args) {
        List<Product> products = Arrays.asList(
            new Product("Product A", 10.0),
            new Product("Product B", 20.5),
            new Product("Product C", 15.8)
        );

        // Collect the products into an unmodifiable Map with the product name as the key and price as the value
        Map<String, Double> productPriceMap = products.stream()
                                                      .collect(Collectors.toUnmodifiableMap(
                                                          Product::getName,
                                                          Product::getPrice
                                                      ));

        System.out.println("Product Price Map: " + productPriceMap);

        // Attempting to modify the map will result in an UnsupportedOperationException
        // productPriceMap.put("Product D", 30.0); // Uncommenting this line will throw an exception
    }
}

Output:

Product Price Map: {Product A=10.0, Product B=20.5, Product C=15.8}

Handling Duplicate Keys with Merge Function

This example shows how to use toUnmodifiableMap() with a merge function to handle collisions between values associated with the same key.

Example

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class MergeFunctionExample {
    public static void main(String[] args) {
        List<String> words = Arrays.asList("apple", "banana", "cherry", "apricot");

        // Collect the words into an unmodifiable Map with the first letter as the key and concatenated words as the value
        Map<Character, String> wordMap = words.stream()
                                              .collect(Collectors.toUnmodifiableMap(
                                                  word -> word.charAt(0),
                                                  word -> word,
                                                  (existing, replacement) -> existing + ", " + replacement
                                              ));

        System.out.println("Word Map: " + wordMap);
    }
}

Output:

Word Map: {c=cherry, b=banana, a=apple, apricot}

Real-World Use Case

Grouping Employees by Department

In real-world applications, the toUnmodifiableMap() method can be used to collect employees into an unmodifiable map based on their department.

Example

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class EmployeeDepartmentExample {
    static class Employee {
        String name;
        String department;

        Employee(String name, String department) {
            this.name = name;
            this.department = department;
        }

        String getName() {
            return name;
        }

        String getDepartment() {
            return department;
        }
    }

    public static void main(String[] args) {
        List<Employee> employees = Arrays.asList(
            new Employee("Alice", "HR"),
            new Employee("Bob", "IT"),
            new Employee("Charlie", "HR"),
            new Employee("David", "Finance")
        );

        // Collect the employees into an unmodifiable Map with the department as the key and names as the value
        Map<String, String> departmentMap = employees.stream()
                                                     .collect(Collectors.toUnmodifiableMap(
                                                         Employee::getDepartment,
                                                         Employee::getName,
                                                         (existing, replacement) -> existing + ", " + replacement
                                                     ));

        System.out.println("Department Map: " + departmentMap);

        // Attempting to modify the map will result in an UnsupportedOperationException
        // departmentMap.put("Marketing", "Eve"); // Uncommenting this line will throw an exception
    }
}

Output:

Department Map: {Finance=David, IT=Bob, HR=Alice, Charlie}

Conclusion

The Collectors.toUnmodifiableMap() method is used to collect elements of a stream into an unmodifiable Map. This method is particularly useful for creating maps that should not be modified after their creation, ensuring immutability. By understanding and using this method, you can efficiently manage immutable mapping operations in your Java applications.

Comments