Map in Java
Learn about key-value pair collections
💡 Think of a Map like a dictionary - each word (key) has its meaning (value)! You look up the word to find its definition. Just like you can't have the same word twice in a dictionary, each key in a Map must be unique, but values can repeat!
📖 What is a Map?
A Map is an object that stores key-value pairs. Each key maps to exactly one value. Maps are perfect for fast lookup, where you need to find data based on a unique identifier. Keys must be unique, but values can be duplicated.
import java.util.HashMap;import java.util.Map;public class BasicHashMap { public static void main(String[] args) { // Creating a HashMap Map<String, String> capitals = new HashMap<>(); // Adding key-value pairs using put() capitals.put("USA", "Washington DC"); capitals.put("France", "Paris"); capitals.put("Japan", "Tokyo"); capitals.put("India", "New Delhi"); System.out.println("Capitals: " + capitals); // Getting values by key String usCapital = capitals.get("USA"); System.out.println("\nCapital of USA: " + usCapital); // Checking if key exists boolean hasFrance = capitals.containsKey("France"); System.out.println("Has France? " + hasFrance); // true // Checking if value exists boolean hasParis = capitals.containsValue("Paris"); System.out.println("Has Paris? " + hasParis); // true // Size of the map System.out.println("\nTotal entries: " + capitals.size()); // Updating a value (put with existing key) capitals.put("USA", "New York"); // Replaces Washington DC System.out.println("Updated USA: " + capitals.get("USA")); // Removing an entry capitals.remove("Japan"); System.out.println("After removing Japan: " + capitals); // Using getOrDefault String ukCapital = capitals.getOrDefault("UK", "Not Found"); System.out.println("\nUK Capital: " + ukCapital); // Not Found }}🔍 🗂️ Types of Maps
Java provides different Map implementations for different scenarios:
HashMap
Fastest lookup, uses hashing, no guaranteed order, allows one null key
LinkedHashMap
Maintains insertion order or access order, slightly slower than HashMap
TreeMap
Keys sorted in natural order or by comparator, slowest but sorted
Hashtable
Thread-safe, legacy class, no null keys or values (use ConcurrentHashMap instead)
import java.util.*;public class ComparingMapTypes { public static void main(String[] args) { // Same data added to different maps String[][] countries = { {"USA", "Washington DC"}, {"France", "Paris"}, {"Japan", "Tokyo"}, {"India", "New Delhi"} }; // 1. HashMap - Fast, no guaranteed order Map<String, String> hashMap = new HashMap<>(); for (String[] pair : countries) { hashMap.put(pair[0], pair[1]); } System.out.println("HashMap (random order):"); hashMap.forEach((k, v) -> System.out.println(" " + k + " -> " + v)); // 2. LinkedHashMap - Maintains insertion order Map<String, String> linkedHashMap = new LinkedHashMap<>(); for (String[] pair : countries) { linkedHashMap.put(pair[0], pair[1]); } System.out.println("\nLinkedHashMap (insertion order):"); linkedHashMap.forEach((k, v) -> System.out.println(" " + k + " -> " + v)); // 3. TreeMap - Sorted by keys Map<String, String> treeMap = new TreeMap<>(); for (String[] pair : countries) { treeMap.put(pair[0], pair[1]); } System.out.println("\nTreeMap (sorted by key):"); treeMap.forEach((k, v) -> System.out.println(" " + k + " -> " + v)); // TreeMap specific methods TreeMap<String, String> sortedMap = (TreeMap<String, String>) treeMap; System.out.println("\nFirst key: " + sortedMap.firstKey()); System.out.println("Last key: " + sortedMap.lastKey()); }}📞 Real-World Example: Phone Book
import java.util.HashMap;import java.util.Map;public class PhoneBook { private Map<String, String> contacts; public PhoneBook() { this.contacts = new HashMap<>(); } // Add a contact public void addContact(String name, String phoneNumber) { contacts.put(name, phoneNumber); System.out.println("Added: " + name + " -> " + phoneNumber); } // Update a contact public void updateContact(String name, String newNumber) { if (contacts.containsKey(name)) { String oldNumber = contacts.put(name, newNumber); System.out.println("Updated " + name + " from " + oldNumber + " to " + newNumber); } else { System.out.println(name + " not found!"); } } // Find a phone number public String findNumber(String name) { return contacts.getOrDefault(name, "Contact not found"); } // Remove a contact public void removeContact(String name) { if (contacts.remove(name) != null) { System.out.println("Removed: " + name); } else { System.out.println(name + " not found!"); } } // Check if contact exists public boolean hasContact(String name) { return contacts.containsKey(name); } // Print all contacts public void printAllContacts() { System.out.println("\n=== Phone Book ==="); if (contacts.isEmpty()) { System.out.println("No contacts!"); } else { contacts.forEach((name, number) -> System.out.println(name + ": " + number)); } System.out.println("Total contacts: " + contacts.size()); } public static void main(String[] args) { PhoneBook phoneBook = new PhoneBook(); // Add contacts phoneBook.addContact("Alice", "555-1234"); phoneBook.addContact("Bob", "555-5678"); phoneBook.addContact("Charlie", "555-9012"); // Look up a number System.out.println("\nAlice's number: " + phoneBook.findNumber("Alice")); // Update a contact phoneBook.updateContact("Bob", "555-0000"); // Print all contacts phoneBook.printAllContacts(); // Remove a contact phoneBook.removeContact("Charlie"); phoneBook.printAllContacts(); // Try to find removed contact System.out.println("\nCharlie's number: " + phoneBook.findNumber("Charlie")); }}📊 Real-World Example: Word Counter
import java.util.*;public class WordCounter { public static void main(String[] args) { String text = "the quick brown fox jumps over the lazy dog the fox is quick"; // Count word frequencies Map<String, Integer> wordCount = new HashMap<>(); // Split text into words String[] words = text.split("\\s+"); // Count each word for (String word : words) { word = word.toLowerCase(); // Method 1: Traditional way // if (wordCount.containsKey(word)) { // wordCount.put(word, wordCount.get(word) + 1); // } else { // wordCount.put(word, 1); // } // Method 2: Using getOrDefault (better) wordCount.put(word, wordCount.getOrDefault(word, 0) + 1); // Method 3: Using merge (best) // wordCount.merge(word, 1, Integer::sum); } // Print word frequencies System.out.println("Word Frequencies:"); wordCount.forEach((word, count) -> System.out.println(word + ": " + count)); // Find most common word String mostCommon = null; int maxCount = 0; for (Map.Entry<String, Integer> entry : wordCount.entrySet()) { if (entry.getValue() > maxCount) { maxCount = entry.getValue(); mostCommon = entry.getKey(); } } System.out.println("\nMost common word: '" + mostCommon + "' (appears " + maxCount + " times)"); // Sort by frequency (descending) System.out.println("\nSorted by frequency:"); wordCount.entrySet().stream() .sorted((e1, e2) -> e2.getValue().compareTo(e1.getValue())) .forEach(e -> System.out.println(e.getKey() + ": " + e.getValue())); // Words that appear more than once System.out.println("\nWords appearing more than once:"); wordCount.entrySet().stream() .filter(e -> e.getValue() > 1) .forEach(e -> System.out.println(e.getKey() + ": " + e.getValue())); }}🎓 Real-World Example: Student ID System
import java.util.*;class Student { String name; int age; double gpa; public Student(String name, int age, double gpa) { this.name = name; this.age = age; this.gpa = gpa; } @Override public String toString() { return name + " (Age: " + age + ", GPA: " + gpa + ")"; }}public class StudentIDSystem { private Map<String, Student> students; public StudentIDSystem() { this.students = new HashMap<>(); } // Register a student public void registerStudent(String id, String name, int age, double gpa) { Student student = new Student(name, age, gpa); students.put(id, student); System.out.println("Registered: " + id + " -> " + student); } // Find student by ID public Student findStudent(String id) { return students.get(id); } // Update student GPA public void updateGPA(String id, double newGPA) { Student student = students.get(id); if (student != null) { student.gpa = newGPA; System.out.println("Updated " + id + " GPA to " + newGPA); } else { System.out.println("Student " + id + " not found!"); } } // Get all students with GPA above threshold public void printHighPerformers(double threshold) { System.out.println("\nStudents with GPA >= " + threshold + ":"); students.forEach((id, student) -> { if (student.gpa >= threshold) { System.out.println(" " + id + ": " + student); } }); } // Print all students public void printAllStudents() { System.out.println("\n=== All Students ==="); students.forEach((id, student) -> System.out.println(id + ": " + student)); System.out.println("Total students: " + students.size()); } public static void main(String[] args) { StudentIDSystem system = new StudentIDSystem(); // Register students system.registerStudent("S001", "Alice", 20, 3.8); system.registerStudent("S002", "Bob", 21, 3.5); system.registerStudent("S003", "Charlie", 19, 3.9); system.registerStudent("S004", "David", 22, 3.2); // Find a student System.out.println("\nLooking up S002:"); Student bob = system.findStudent("S002"); System.out.println(bob); // Update GPA system.updateGPA("S002", 3.7); // Print all students system.printAllStudents(); // High performers system.printHighPerformers(3.7); }}🔧 Common Map Operations
import java.util.*;public class MapOperations { public static void main(String[] args) { Map<String, Integer> scores = new HashMap<>(); // 1. Adding entries scores.put("Alice", 95); scores.put("Bob", 87); scores.put("Charlie", 92); // 2. putIfAbsent - only add if key doesn't exist scores.putIfAbsent("Alice", 100); // Won't replace 95 scores.putIfAbsent("David", 88); // Will add // 3. Iterating through map System.out.println("Using entrySet (most efficient):"); for (Map.Entry<String, Integer> entry : scores.entrySet()) { System.out.println(entry.getKey() + ": " + entry.getValue()); } System.out.println("\nUsing keySet:"); for (String name : scores.keySet()) { System.out.println(name + ": " + scores.get(name)); } System.out.println("\nUsing values:"); for (Integer score : scores.values()) { System.out.println("Score: " + score); } System.out.println("\nUsing forEach:"); scores.forEach((name, score) -> System.out.println(name + ": " + score)); // 4. Compute methods scores.compute("Alice", (key, val) -> val + 5); // Add 5 to Alice's score scores.computeIfAbsent("Eve", key -> 90); // Add Eve with score 90 scores.computeIfPresent("Bob", (key, val) -> val + 10); // Add 10 to Bob // 5. merge - combine values scores.merge("Charlie", 8, Integer::sum); // Add 8 to Charlie's score // 6. replace methods scores.replace("David", 95); // Replace David's score scores.replace("Bob", 97, 100); // Replace only if current value is 97 // 7. Removing entries scores.remove("Eve"); // Remove by key scores.remove("Alice", 100); // Remove only if value matches System.out.println("\nFinal scores: " + scores); // 8. Bulk operations Map<String, Integer> moreScores = new HashMap<>(); moreScores.put("Frank", 85); moreScores.put("Grace", 93); scores.putAll(moreScores); // Add all entries // 9. Clear and size System.out.println("Total entries: " + scores.size()); boolean isEmpty = scores.isEmpty(); }}🔑 Key Concepts
Key-Value Pairs
Each entry has a unique key and its associated value
('USA' -> 'Washington DC'), ('France' -> 'Paris')
Unique Keys
Each key can appear only once, adding same key replaces value
Adding ('USA' -> 'New York') replaces the previous value
Fast Lookup
Finding a value by key is very fast O(1) for HashMap
map.get('USA') instantly returns 'Washington DC'
No Duplicate Keys
Keys must be unique but values can repeat
Multiple countries can have same currency
✨ Best Practices
- ✓Use HashMap for best performance when order doesn't matter
- ✓Use LinkedHashMap when you need predictable iteration order
- ✓Use TreeMap when you need keys sorted
- ✓Keys should be immutable (String, Integer, etc.) and properly implement equals() and hashCode()
- ✓Check if key exists with containsKey() before using get()
- ✓Use getOrDefault() to provide fallback values
- ✓Prefer Map interface type over implementation in declarations
- ✓Consider ConcurrentHashMap for thread-safe operations instead of Hashtable
💼 Interview Tips
- •HashMap uses array of linked lists/trees internally (buckets)
- •Default initial capacity is 16, load factor is 0.75
- •HashMap becomes TreeMap-like when bucket has 8+ elements (JDK 8+)
- •put() returns the previous value for the key (or null)
- •HashMap allows one null key and multiple null values
- •TreeMap doesn't allow null keys (NullPointerException)
- •Know how hashCode() and equals() affect HashMap performance
- •Understand collision resolution with chaining
- •entrySet() is more efficient than keySet() when you need both key and value