Introduction to Map and Key-Value Data Structures in Java
Course: Core Java Training
Topic: Introduction to Map and Key-Value Data Structures
Course Link: Core Java Training Course
Demo Link: Register for a Free Course Demo
Website: JustAcademy
1. Introduction to Map in Java
In Java, a Map is an interface in the Java Collections Framework that stores data as key-value pairs. Each key is associated with a value, allowing a program to retrieve, update, or remove a value using its corresponding key.
Maps are useful when data needs to be identified by a unique key instead of accessed only through a numeric index. For example, a student ID can be used as a key to retrieve a student's name, or a product code can identify a product's price.
The Map interface belongs to the java.util package. Unlike List and Set, it is not a subtype of the Collection interface.
Example of Key-Value Data
| Key |
Value |
| 101 |
Aarav |
| 102 |
Priya |
| 103 |
Rahul |
In this example, student IDs are keys and student names are values. If the program needs the name associated with ID 102, it can retrieve the value Priya using that key.
2. What Is a Key-Value Pair?
A key-value pair is a combination of two related pieces of information:
- Key: Identifies a mapping in the Map.
- Value: The data associated with that key.
For example, in "India" → "New Delhi", the key is India and the value is New Delhi.
Important Characteristics
- Each key can appear only once in a Map.
- Different keys can have the same value.
- Values may be duplicated.
- Some Map implementations permit null keys or values, while others restrict them.
- Adding a value using an existing key generally replaces the previous value associated with that key.
- Keys are used to locate their associated values.
3. Understanding the Map Interface
The Map interface defines methods for inserting, retrieving, updating, removing, and checking key-value mappings. Common implementations include HashMap, LinkedHashMap, TreeMap, and Hashtable.
Basic Syntax
Map<KeyType, ValueType> map = new HashMap<>();
Here, KeyType represents the type of the keys and ValueType represents the type of the values. Java generics provide compile-time type checking for these types.
Example
import java.util.HashMap;
import java.util.Map;
public class MapIntroduction {
public static void main(String[] args) {
Map<Integer, String> students = new HashMap<>();
students.put(101, "Aarav");
students.put(102, "Priya");
students.put(103, "Rahul");
System.out.println(students);
System.out.println(students.get(102));
}
}
Explanation:
Map<Integer, String> defines integer keys and string values.
new HashMap<>() creates a Map implementation.
put() inserts key-value mappings.
get(102) retrieves the value associated with key 102.
Expected retrieval output:
Priya
The order of entries printed from a HashMap is not guaranteed.
4. Why Do We Use Map in Java?
Maps are particularly useful when information is naturally organized around identifiers or lookup keys.
- Fast lookups: Retrieve a value by its key without searching manually through a list.
- Data association: Connect an identifier with related information.
- Counting frequency: Track how many times a word or item appears.
- Configuration storage: Store settings as property names and values.
- Data indexing: Find objects using IDs, usernames, codes, or other identifiers.
- Caching: Associate request parameters or resource identifiers with previously calculated results.
5. Common Map Implementations
Java provides multiple implementations of the Map interface. Each has different ordering, performance, and null-handling characteristics.
| Implementation |
Ordering |
Null Handling |
Typical Use |
HashMap |
No guaranteed iteration order |
Allows one null key and null values |
General-purpose key-value storage |
LinkedHashMap |
Normally preserves insertion order |
Allows one null key and null values |
Predictable iteration order |
TreeMap |
Sorted by keys using natural ordering or a comparator |
Normally does not allow null keys with natural ordering; null values are allowed |
Sorted key-value data and range queries |
Hashtable |
No guaranteed iteration order |
Does not allow null keys or values |
Legacy synchronized Map implementation |
ConcurrentHashMap |
No guaranteed iteration order |
Does not allow null keys or values |
Concurrent access from multiple threads |
5.1 HashMap
HashMap is a widely used implementation of the Map interface. It uses hashing to organize keys and generally provides efficient insertion, lookup, and removal operations.
import java.util.HashMap;
import java.util.Map;
public class HashMapExample {
public static void main(String[] args) {
Map<String, Integer> prices = new HashMap<>();
prices.put("Laptop", 55000);
prices.put("Keyboard", 1500);
prices.put("Mouse", 700);
System.out.println(prices.get("Laptop"));
}
}
Output:
55000
Use HashMap when you need general-purpose key-value storage and do not require a particular iteration order.
5.2 LinkedHashMap
LinkedHashMap maintains a predictable iteration order. By default, that order is insertion order. It can also be configured for access-order behavior, which can be useful when implementing cache policies.
import java.util.LinkedHashMap;
import java.util.Map;
public class LinkedHashMapExample {
public static void main(String[] args) {
Map<Integer, String> employees = new LinkedHashMap<>();
employees.put(1, "Neha");
employees.put(2, "Amit");
employees.put(3, "Karan");
employees.forEach((id, name) ->
System.out.println(id + " : " + name)
);
}
}
Output:
1 : Neha
2 : Amit
3 : Karan
5.3 TreeMap
TreeMap stores entries in sorted key order. Keys must be mutually comparable using their natural ordering or a supplied comparator.
import java.util.Map;
import java.util.TreeMap;
public class TreeMapExample {
public static void main(String[] args) {
Map<Integer, String> products = new TreeMap<>();
products.put(30, "Monitor");
products.put(10, "Laptop");
products.put(20, "Keyboard");
System.out.println(products);
}
}
Example output:
{10=Laptop, 20=Keyboard, 30=Monitor}
Use TreeMap when sorted keys or operations such as finding a range of keys are important.
6. Important Methods of the Map Interface
| Method |
Purpose |
Example |
put(key, value) |
Adds a mapping or replaces the value for an existing key. |
map.put("A", 10); |
get(key) |
Returns the value associated with a key, or null if no mapping is found. |
map.get("A"); |
remove(key) |
Removes the mapping for a key. |
map.remove("A"); |
containsKey(key) |
Checks whether a key exists. |
map.containsKey("A"); |
containsValue(value) |
Checks whether a value is present. |
map.containsValue(10); |
size() |
Returns the number of mappings. |
map.size(); |
isEmpty() |
Checks whether the Map contains no mappings. |
map.isEmpty(); |
clear() |
Removes all mappings. |
map.clear(); |
keySet() |
Returns a Set view of the keys. |
map.keySet(); |
values() |
Returns a Collection view of the values. |
map.values(); |
entrySet() |
Returns a Set view of the key-value entries. |
map.entrySet(); |
getOrDefault(key, defaultValue) |
Returns the mapped value or a default when the key is absent. |
map.getOrDefault("B", 0); |
putIfAbsent(key, value) |
Adds a mapping when the key is absent or currently mapped to null, subject to implementation behavior. |
map.putIfAbsent("B", 20); |
7. Inserting and Updating Data with put()
The put() method inserts a new key-value mapping. If the key already exists, its associated value is replaced.
import java.util.HashMap;
import java.util.Map;
public class PutExample {
public static void main(String[] args) {
Map<String, String> countries = new HashMap<>();
countries.put("IN", "India");
countries.put("US", "United States");
countries.put("IN", "Republic of India");
System.out.println(countries.get("IN"));
}
}
Output:
Republic of India
Because keys are unique, inserting the same key does not create a second independent mapping for that key.
8. Retrieving Values with get()
The get() method looks up a value using its key. If the key is not present, it returns null. However, a Map may also explicitly map a key to null, so get() alone cannot always distinguish these situations.
Map<Integer, String> users = new HashMap<>();
users.put(1, "Ananya");
System.out.println(users.get(1));
System.out.println(users.get(2));
System.out.println(users.containsKey(2));
Output:
Ananya
null
false
Use containsKey() when it is necessary to determine whether a key has a mapping, even if the mapped value could be null.
9. Iterating Through a Map
Iteration means accessing the entries in a Map one by one. Java offers several ways to iterate, depending on whether you need keys, values, or both.
9.1 Iterating Through Keys
Map<Integer, String> students = new HashMap<>();
students.put(101, "Aarav");
students.put(102, "Priya");
for (Integer id : students.keySet()) {
System.out.println(id);
}
9.2 Iterating Through Values
for (String name : students.values()) {
System.out.println(name);
}
9.3 Iterating Through Entries
When both the key and value are required, entrySet() is often the clearest option.
for (Map.Entry<Integer, String> entry : students.entrySet()) {
System.out.println(
"ID: " + entry.getKey() +
", Name: " + entry.getValue()
);
}
9.4 Using forEach()
students.forEach((id, name) ->
System.out.println(id + " - " + name)
);
Remember that iteration order depends on the Map implementation. A HashMap does not guarantee a specific order, while a default LinkedHashMap preserves insertion order and a TreeMap sorts by key.
10. Map and Other Collection Types
| Feature |
List |
Set |
Map |
| Stores |
Individual elements |
Unique elements |
Key-value mappings |
| Duplicates |
Allows duplicate elements |
Does not allow duplicate elements according to equality rules |
Keys are unique; values may repeat |
| Access |
Often by index or iteration |
Usually by membership or iteration |
By key or iteration |
| Examples |
ArrayList, LinkedList |
HashSet, TreeSet |
HashMap, TreeMap |
| Typical purpose |
Maintain a sequence of items |
Maintain unique items |
Associate identifiers with values |
11. How HashMap Works at a High Level
A HashMap uses a key's hash code to help locate the storage location for a mapping. It also uses equality checks to distinguish keys that may have the same hash code.
- Hash calculation: Java obtains a hash code from the key.
- Bucket selection: The hash is used to determine an internal bucket location.
- Collision handling: If multiple keys map to the same bucket, the Map handles the collision internally.
- Key comparison: Equality checks help identify whether an existing key matches the requested key.
- Value access: The associated value is retrieved or updated.
For well-distributed hashes, common HashMap operations such as get() and put() generally have expected constant-time performance. Heavy collisions can affect performance.
Why equals() and hashCode() Matter
When custom objects are used as keys, their equals() and hashCode() implementations must follow the Java contract. If two keys are equal according to equals(), they must return the same hash code.
import java.util.Objects;
class EmployeeKey {
private final int id;
EmployeeKey(int id) {
this.id = id;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (!(obj instanceof EmployeeKey)) return false;
EmployeeKey other = (EmployeeKey) obj;
return id == other.id;
}
@Override
public int hashCode() {
return Objects.hash(id);
}
}
Use stable key fields whenever possible. Changing fields involved in a key's hashing or equality after inserting the key can make the mapping difficult to retrieve correctly.
12. Using Objects as Map Keys and Values
Maps are not limited to primitive wrapper types and strings. They can store objects as keys or values, provided the chosen types and implementations meet the application's requirements.
import java.util.HashMap;
import java.util.Map;
class Student {
String name;
int age;
Student(String name, int age) {
this.name = name;
this.age = age;
}
}
public class ObjectValueExample {
public static void main(String[] args) {
Map<Integer, Student> students = new HashMap<>();
students.put(101, new Student("Aarav", 20));
students.put(102, new Student("Priya", 21));
Student student = students.get(101);
if (student != null) {
System.out.println(student.name);
System.out.println(student.age);
}
}
}
Output:
Aarav
20
This approach is useful when an ID needs to identify a complete object rather than a single text or numeric value.
13. Practical Example: Counting Word Frequency
A common use of a Map is counting how many times each word occurs in a collection of words.
import java.util.HashMap;
import java.util.Map;
public class WordFrequency {
public static void main(String[] args) {
String[] words = {
"java", "map", "java", "collection", "map", "java"
};
Map<String, Integer> frequency = new HashMap<>();
for (String word : words) {
frequency.put(
word,
frequency.getOrDefault(word, 0) + 1
);
}
frequency.forEach((word, count) ->
System.out.println(word + " : " + count)
);
}
}
Possible output:
java : 3
map : 2
collection : 1
The order of these lines is not guaranteed because the example uses a HashMap.
How it works:
- The program reads each word from the array.
getOrDefault(word, 0) retrieves the current count or returns zero when the word is absent.
- The count is increased by one.
put() stores the updated count.
14. Map Default and Utility Methods
Modern Java versions provide helpful Map methods for common operations.
14.1 getOrDefault()
Map<String, Integer> scores = new HashMap<>();
scores.put("Riya", 85);
int riyaScore = scores.getOrDefault("Riya", 0);
int amitScore = scores.getOrDefault("Amit", 0);
System.out.println(riyaScore);
System.out.println(amitScore);
Output:
85
0
14.2 putIfAbsent()
Map<String, String> settings = new HashMap<>();
settings.put("theme", "dark");
settings.putIfAbsent("theme", "light");
settings.putIfAbsent("language", "English");
System.out.println(settings);
The existing non-null theme remains dark, while the absent language setting is added.
14.3 computeIfAbsent()
computeIfAbsent() computes a value when a key is absent or currently mapped to null, then stores a non-null result.
Map<String, Integer> lengths = new HashMap<>();
lengths.computeIfAbsent("Java", key -> key.length());
System.out.println(lengths.get("Java"));
Output:
4
15. Common Mistakes When Using Map
| Mistake |
Why It Is a Problem |
Better Practice |
| Assuming HashMap order |
Iteration order is not guaranteed. |
Use LinkedHashMap or TreeMap when order matters. |
| Using duplicate keys expecting separate entries |
A key has only one mapping at a time. |
Use a collection as the value if one key must represent multiple items. |
| Assuming get() returning null means the key is absent |
The key may be explicitly mapped to null. |
Use containsKey() when the distinction matters. |
| Using mutable objects as keys |
Changing fields involved in hashing or equality can interfere with lookups. |
Prefer immutable keys or stable key fields. |
| Choosing a Map without considering concurrency |
Ordinary HashMap is not designed for unsynchronized concurrent modifications. |
Consider ConcurrentHashMap or suitable synchronization. |
| Ignoring type safety |
Raw types can cause runtime type errors. |
Use generics such as Map<String, Integer>. |
16. Choosing the Right Map Implementation
- Choose
HashMap for general-purpose lookups without ordering requirements.
- Choose
LinkedHashMap when predictable insertion-order iteration is needed.
- Choose
TreeMap when keys must remain sorted or range-based operations are useful.
- Choose
ConcurrentHashMap when multiple threads need concurrent access and updates.
- Use
Hashtable mainly when working with legacy code; newer concurrency designs usually have better alternatives.
For performance, choose based on actual requirements and measure with realistic data when the choice is important. A sorted Map, an insertion-ordered Map, and a hash-based Map solve related but different problems.
17. Best Practices for Working with Maps
- Declare variables using the
Map interface when the implementation details do not need to be exposed.
- Use meaningful key and value types with generics.
- Choose an implementation based on ordering, null handling, concurrency, and lookup needs.
- Use
entrySet() when iterating over both keys and values.
- Use
getOrDefault() for straightforward default-value lookups.
- Override
equals() and hashCode() correctly for custom key objects.
- Avoid modifying a Map structurally while iterating over it unless the chosen iteration mechanism explicitly supports the operation.
- Do not assume a Map is thread-safe unless its implementation and usage provide the required guarantees.
- Document what each key represents, especially in complex applications.
18. Hands-On Exercises
Exercise 1: Student Records
Create a HashMap where student roll numbers are keys and student names are values. Insert five students and retrieve a name using a roll number.
Exercise 2: Product Prices
Create a Map of product names and prices. Update one product's price, remove another product, and print the remaining entries.
Exercise 3: Character Frequency
Write a Java program that counts how many times each character occurs in a string using a Map.
Exercise 4: Sorted Employee IDs
Use a TreeMap to store employee IDs and names. Insert IDs in random order and verify that iteration follows sorted key order.
Exercise 5: Word Counter
Read a sentence, split it into words, and use a Map to count each word's frequency. Consider normalizing case and removing punctuation.
19. Mini Project: Student Marks Management System
Objective: Create a simple Java application that stores student marks using student IDs as keys.
Requirements
- Store student IDs and marks in a
Map<Integer, Integer>.
- Add marks for a new student.
- Retrieve marks using a student ID.
- Update marks when a student's score changes.
- Check whether a student ID exists.
- Display all student records.
Sample Implementation
import java.util.HashMap;
import java.util.Map;
public class StudentMarksSystem {
public static void main(String[] args) {
Map<Integer, Integer> marks = new HashMap<>();
marks.put(101, 88);
marks.put(102, 92);
marks.put(103, 76);
System.out.println("Marks of 102: " + marks.get(102));
marks.put(103, 81);
if (marks.containsKey(101)) {
System.out.println("Student 101 exists.");
}
System.out.println("All student marks:");
for (Map.Entry<Integer, Integer> entry : marks.entrySet()) {
System.out.println(
"Student ID: " + entry.getKey() +
", Marks: " + entry.getValue()
);
}
}
}
This mini project demonstrates storing, retrieving, updating, checking, and iterating through Map entries.
20. Interview Questions and Answers
Q1. What is a Map in Java?
A Map is an interface that stores key-value mappings. Each key is unique within the Map, while values can be duplicated.
Q2. Is Map part of the Collection interface?
No. The Map interface is part of the Java Collections Framework, but it does not extend the Collection interface.
Q3. Can a Map contain duplicate keys?
No. Each key can have only one current mapping. Adding an existing key generally replaces its previous value.
Q4. Can multiple keys have the same value?
Yes. A Map allows different keys to map to equal values.
Q5. What is the difference between HashMap and TreeMap?
HashMap does not guarantee iteration order and is generally efficient for ordinary lookups. TreeMap maintains keys in sorted order and supports sorted-map operations.
Q6. What is the purpose of keySet(), values(), and entrySet()?
keySet() provides a view of keys, values() provides a view of values, and entrySet() provides a view of key-value entries.
Q7. What happens when put() is called with an existing key?
The existing mapping is updated with the new value, and the previous value is returned by put().
Q8. What is the difference between get() and containsKey()?
get() retrieves a value, while containsKey() checks whether a mapping exists for a key. The latter helps distinguish an absent key from a key mapped to null.
Q9. Can objects be used as Map keys?
Yes. Custom objects can be keys. For hash-based Maps, equals() and hashCode() must obey their contract, and key fields should remain stable while the object is used as a key.
Q10. Is HashMap thread-safe?
No. HashMap does not provide general thread-safety for concurrent updates. Consider ConcurrentHashMap or appropriate synchronization for multi-threaded use.
21. Quick Revision Checklist
- A Map stores key-value pairs.
- Keys are unique, while values can repeat.
put() inserts or updates a mapping.
get() retrieves a value using its key.
containsKey() checks whether a key exists.
keySet(), values(), and entrySet() support iteration.
HashMap does not guarantee iteration order.
LinkedHashMap normally preserves insertion order.
TreeMap sorts keys.
- Custom hash-based keys need correct
equals() and hashCode() implementations.
- Choose a concurrent Map or synchronization when thread safety is required.
22. Conclusion
The Map interface is a fundamental part of Java's Collections Framework. It allows programs to associate unique keys with values, making it useful for lookups, counting, configuration storage, indexing, caching, and managing application records.
Understanding key-value pairs, common methods, iteration techniques, and the differences between HashMap, LinkedHashMap, and TreeMap will help you select the right data structure for different programming problems. Practice the exercises and mini project to strengthen your Core Java skills.
Continue Learning: Visit the Core Java Training course, register for a course demo, or explore the JustAcademy website.