The Map interface in Java is part of the java.util package and represents a collection of key-value pairs.
Unlike the Collection interface, which focuses on individual elements, the Map interface associates each key with a specific value. Keys in a Map must be unique, but values can be duplicated.
Table of Contents
This tutorial covers:
Overview of the Map interface.
Common implementations (HashMap, LinkedHashMap, TreeMap).
Code examples demonstrating various Map operations.
1. Map Interface Overview
Key Methods in the Map Interface
put(K key, V value): Associates the specified value with the specified key. If the key already exists, its value is updated.
get(Object key): Returns the value associated with the specified key or null if the key doesn't exist.
remove(Object key): Removes the key-value pair for the specified key.
containsKey(Object key): Returns true if the map contains the specified key.
containsValue(Object value): Returns true if the map contains the specified value.
keySet(): Returns a Set of all keys in the map.
values(): Returns a Collection of all values in the map.
entrySet(): Returns a Set of all key-value pairs (as Map.Entry objects) in the map.
2. HashMap Implementation Example
A HashMap is the most commonly used implementation of the Map interface. It stores key-value pairs in an unsorted and unordered manner. Keys are unique, and the map allows null values and one null key.
import java.util.HashMap; import java.util.Map; public class HashMapExample { public static void main(String[] args) { // Creating a HashMap Map<String, Integer> ageMap = new HashMap<>(); // Adding key-value pairs using put() ageMap.put("Alice", 30); ageMap.put("Bob", 25); ageMap.put("Charlie", 35); // Accessing values using get() System.out.println("Alice's age: " + ageMap.get("Alice")); // 30 System.out.println("Bob's age: " + ageMap.get("Bob")); // 25 // Checking if a key or value exists System.out.println("Contains key 'Charlie'? " + ageMap.containsKey("Charlie")); // true System.out.println("Contains value 30? " + ageMap.containsValue(30)); // true // Removing an entry ageMap.remove("Alice"); System.out.println("Map after removing Alice: " + ageMap); // Iterating over keys and values System.out.println("All keys: " + ageMap.keySet()); System.out.println("All values: " + ageMap.values()); // Iterating using entrySet() for (Map.Entry<String, Integer> entry : ageMap.entrySet()) { System.out.println(entry.getKey() + ": " + entry.getValue()); } } }
Explanation:
put(): Adds key-value pairs to the map. If the key exists, the value is replaced.
get(): Retrieves the value associated with a specific key.
containsKey() and containsValue(): Check if a key or value exists in the map.
remove(): Removes a key-value pair based on the key.
keySet() and values(): Retrieve all keys and values, respectively.
entrySet(): Returns a set of Map.Entry objects, allowing iteration over key-value pairs.
3. LinkedHashMap Implementation Example
A LinkedHashMap maintains the insertion order of its key-value pairs. This means that when you iterate over the map, the keys and values appear in the order in which they were inserted.
import java.util.LinkedHashMap; import java.util.Map; public class LinkedHashMapExample { public static void main(String[] args) { // Creating a LinkedHashMap Map<String, Integer> orderedMap = new LinkedHashMap<>(); // Adding key-value pairs orderedMap.put("Apple", 100); orderedMap.put("Banana", 50); orderedMap.put("Cherry", 75); // Iterating over the map (will maintain insertion order) System.out.println("Iterating over LinkedHashMap:"); for (Map.Entry<String, Integer> entry : orderedMap.entrySet()) { System.out.println(entry.getKey() + ": " + entry.getValue()); } // Accessing values in insertion order System.out.println("First item inserted: " + orderedMap.entrySet().iterator().next()); } }
Explanation:
A LinkedHashMap maintains the order in which key-value pairs are inserted, unlike HashMap, which has no specific order.
You can iterate through the map and expect the elements to appear in the order of insertion.
4. TreeMap Implementation Example
A TreeMap stores its key-value pairs in sorted order according to the natural ordering of the keys (or a custom Comparator if provided).
import java.util.Map; import java.util.TreeMap; public class TreeMapExample { public static void main(String[] args) { // Creating a TreeMap Map<String, Integer> sortedMap = new TreeMap<>(); // Adding key-value pairs (keys will be sorted in natural order) sortedMap.put("Banana", 50); sortedMap.put("Apple", 100); sortedMap.put("Cherry", 75); // Iterating over the map (keys will be sorted) System.out.println("Iterating over TreeMap:"); for (Map.Entry<String, Integer> entry : sortedMap.entrySet()) { System.out.println(entry.getKey() + ": " + entry.getValue()); } } }
Explanation:
A TreeMap sorts its keys in natural order (lexicographically for strings).
When iterating through a TreeMap, the entries are returned in sorted order based on the keys.
5. Iterating Over a Map
Java offers several ways to iterate over a Map. Let’s look at a few common approaches.
Example: Iterating Over Key-Value Pairs Using entrySet()
import java.util.HashMap; import java.util.Map; public class MapIterationExample { public static void main(String[] args) { Map<String, Integer> map = new HashMap<>(); map.put("A", 1); map.put("B", 2); map.put("C", 3); // Iterating using entrySet() System.out.println("Iterating using entrySet():"); for (Map.Entry<String, Integer> entry : map.entrySet()) { System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue()); } // Iterating using keySet() and get() System.out.println("\nIterating using keySet() and get():"); for (String key : map.keySet()) { System.out.println("Key: " + key + ", Value: " + map.get(key)); } // Iterating using forEach (Java 8+) System.out.println("\nIterating using forEach() (Java 8+):"); map.forEach((key, value) -> System.out.println("Key: " + key + ", Value: " + value)); } }
Explanation:
entrySet(): Returns a set of key-value pairs, allowing you to iterate over both the keys and values simultaneously.
keySet(): Returns a set of keys, and you can retrieve corresponding values using the get() method.
forEach(): Introduced in Java 8, allows for concise iteration over the map.
6. Common Operations on a Map
Example: Basic Operations
import java.util.HashMap; import java.util.Map; public class MapOperationsExample { public static void main(String[] args) { Map<String, String> capitals = new HashMap<>(); // Adding key-value pairs using put() capitals.put("France", "Paris"); capitals.put("Germany", "Berlin"); capitals.put("USA", "Washington D.C."); capitals.put("Japan", "Tokyo"); // Accessing values using get() System.out.println("Capital of Germany: " + capitals.get("Germany")); // Berlin // Checking if a key or value exists System.out.println("Contains key 'USA'? " + capitals.containsKey("USA")); // true System.out.println("Contains value 'Paris'? " + capitals.containsValue("Paris")); // true // Removing a key-value pair capitals.remove("Japan"); System.out.println("Map after removing Japan: " + capitals); // Replacing a value capitals.replace("France", "Marseille"); System.out.println("Map after replacing France's capital: " + capitals); } }
Explanation:
put(): Adds key-value pairs or updates the value if the key already exists.
get(): Retrieves the value associated with the specified key.
remove(): Removes a key-value pair.
replace(): Replaces the value for a specific key.
7. Map of Custom Objects
You can use custom objects as keys or values in a Map, provided the key class implements hashCode() and equals() properly.
Example: Using Custom Objects as Keys
import java.util.HashMap; import java.util.Map; import java.util.Objects; class Employee { String id; String name; Employee(String id, String name) { this.id = id; this.name = name; } @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof Employee)) return false; Employee employee = (Employee) o; return Objects.equals(id, employee.id); } @Override public int hashCode() { return Objects.hash(id); } @Override public String toString() { return name; } } public class CustomObjectMapExample { public static void main(String[] args) { Map<Employee, String> employeeDepartmentMap = new HashMap<>(); // Creating Employee objects Employee emp1 = new Employee("E001", "John Doe"); Employee emp2 = new Employee("E002", "Jane Smith"); // Adding employees to the map employeeDepartmentMap.put(emp1, "HR"); employeeDepartmentMap.put(emp2, "Finance"); // Accessing map entries System.out.println("John's Department: " + employeeDepartmentMap.get(emp1)); // HR System.out.println("Jane's Department: " + employeeDepartmentMap.get(emp2)); // Finance } }
Explanation:
Custom objects can be used as keys in a Map, but you must override equals() and hashCode() to ensure proper functioning.
In this example, Employee objects are used as keys, and their departments are stored as values.
Conclusion
The Map interface in Java is a powerful tool for managing key-value pairs, and it provides several implementations suited for different use cases:
HashMap: For fast, unsorted, and unordered mappings.
LinkedHashMap: For mappings that maintain the order of insertion.
TreeMap: For sorted mappings.
Custom Objects as Keys: Ensure that custom classes properly implement equals() and hashCode().
Using these implementations effectively allows you to manage collections of data in a way that suits the requirements of your project.