Welcome to our Java data structures revision! Today, we will delve deeply into Java Maps. Much like a bookshelf, Maps allow you to quickly select the book (value) you desire by reading its label (key). They are vital in Java for quickly accessing values using keys and for efficiently inserting and deleting keys. So, let's explore Java Maps for a clearer understanding of these concepts.
Before diving into real-world applications, it’s essential to grasp the fundamentals of Java Maps, a crucial data structure for storing data as key-value pairs. Understanding how to define and perform basic operations on them prepares us for more complex implementations.
In Java, keys in a Map
are unique, and you can have many different types as keys like Strings
or Integers
; however, if mutable objects are used as keys, their behavior can be unexpected. In most cases, developers prefer using HashMap<K, V>
which allows fast lookups.
Java1import java.util.HashMap; 2import java.util.Map; 3 4public class Solution { 5 public static void main(String[] args) { 6 // Defining a HashMap 7 Map<String, Integer> ageMap = new HashMap<>(); 8 9 // Adding entries 10 ageMap.put("Alice", 25); 11 ageMap.put("Bob", 30); 12 System.out.println("After adding: "); 13 for (Map.Entry<String, Integer> entry : ageMap.entrySet()) { 14 System.out.println(entry.getKey() + ": " + entry.getValue()); 15 } 16 17 // Updating entries 18 ageMap.put("Alice", 26); // Updates Alice's age 19 System.out.println("\nAfter updating: "); 20 for (Map.Entry<String, Integer> entry : ageMap.entrySet()) { 21 System.out.println(entry.getKey() + ": " + entry.getValue()); 22 } 23 24 // Retrieving values 25 int ageOfAlice = ageMap.containsKey("Alice") ? ageMap.get("Alice") : -1; 26 System.out.println("\nAlice's Age: " + ageOfAlice); 27 28 // Removing entries 29 ageMap.remove("Bob"); 30 System.out.println("\nAfter removing Bob: "); 31 for (Map.Entry<String, Integer> entry : ageMap.entrySet()) { 32 System.out.println(entry.getKey() + ": " + entry.getValue()); 33 } 34 35 // Counting entries 36 int entryCount = ageMap.size(); 37 System.out.println("\nNumber of Entries: " + entryCount); 38 } 39}
- Defining a Map: Use
HashMap<K, V>
whereK
is the type for keys andV
is the type for values. - Adding: Initial addition of entries, printed after insertion.
- Updating: Demonstrates updating the existing entry by reassigning Alice's age.
- Retrieving: Uses
containsKey
to check existence and retrieve values. - Removing: Uses the
remove
method to delete entries. - Counting: Uses the
size
method to get the number of entries.
Now that you're familiar with these operations, let's apply them in a PhoneBook
class.
Imagine storing your friend's contact info in such a way that allows you to search for your friend's name (the key) and instantly find their phone number (the value).
Java1import java.util.HashMap; 2import java.util.Map; 3 4class PhoneBook { 5 private Map<String, String> contacts; 6 7 public PhoneBook() { 8 // Initialize the HashMap 9 contacts = new HashMap<>(); 10 } 11 12 public void addContact(String name, String phoneNumber) { 13 // Add or update a contact 14 contacts.put(name, phoneNumber); 15 } 16 17 public String getPhoneNumber(String name) { 18 // Retrieve a phone number or return "Not Found" 19 return contacts.containsKey(name) ? contacts.get(name) : "Not Found"; 20 } 21} 22 23public class Solution { 24 public static void main(String[] args) { 25 // Create a PhoneBook instance 26 PhoneBook phoneBook = new PhoneBook(); 27 28 // Add contacts 29 phoneBook.addContact("Alice", "123-456-7890"); 30 phoneBook.addContact("Bob", "234-567-8901"); 31 32 // Get and display phone numbers 33 System.out.println(phoneBook.getPhoneNumber("Alice")); // Output: "123-456-7890" 34 System.out.println(phoneBook.getPhoneNumber("Bobby")); // Output: "Not Found" 35 } 36}
In the above code, we create a PhoneBook
class that uses a HashMap
to store contacts. As you can see, Maps simplify the processes of adding, modifying, and accessing information with unique keys.
Java Maps enable a variety of operations for manipulating data, such as adding, retrieving, and deleting key-value pairs, and more. Understanding these operations is crucial for efficient data handling in Java.
To add or update entries in a Map, you use the put
method. If the key exists, the value is updated; if not, a new key-value pair is added. This flexibility allows for dynamic updates and additions to the Map without needing a predefined structure.
The get
method retrieves the value associated with a specific key. It provides a direct way to access values, returning null
if the key does not exist; however, combining it with containsKey
helps in avoiding null
.
Checking if a key exists in the Map can be done using the containsKey
method. This method returns a boolean value — true
if the key exists in the Map, and otherwise false
. This is particularly useful for conditionally handling data based on its existence in the Map.
Deleting an entry is done using the remove
method followed by the key. This operation removes the specified key-value pair from the Map, which is essential for actively managing the contents of the Map.
The size
method provides the number of key-value pairs present in the Map. This is especially useful when you need to know the total number of entries in the Map.
Let’s see how these operations work in the context of a TaskManager
class:
Java1import java.util.HashMap; 2import java.util.Map; 3 4class TaskManager { 5 private Map<String, String> tasks; 6 7 public TaskManager() { 8 // Initialize with an empty HashMap 9 tasks = new HashMap<>(); 10 } 11 12 public void addUpdateTask(String taskName, String status) { 13 // Add a new task or update an existing task 14 tasks.put(taskName, status); 15 } 16 17 public String getTaskStatus(String taskName) { 18 // Retrieve task status or return "Not Found" 19 return tasks.getOrDefault(taskName, "Not Found"); 20 } 21 22 public void deleteTask(String taskName) { 23 // Removes a task using its name 24 if (tasks.containsKey(taskName)) { 25 tasks.remove(taskName); 26 } else { 27 System.out.println("Task '" + taskName + "' not found."); 28 } 29 } 30 31 public int getTaskCount() { 32 // Returns the number of tasks in the TaskManager 33 return tasks.size(); 34 } 35} 36 37public class Solution { 38 public static void main(String[] args) { 39 // Create a TaskManager instance 40 TaskManager myTasks = new TaskManager(); 41 42 // Add tasks and update them 43 myTasks.addUpdateTask("Buy Milk", "Pending"); 44 System.out.println(myTasks.getTaskStatus("Buy Milk")); // Output: Pending 45 46 myTasks.addUpdateTask("Buy Milk", "Completed"); 47 System.out.println(myTasks.getTaskStatus("Buy Milk")); // Output: Completed 48 49 // Delete a task 50 myTasks.deleteTask("Buy Milk"); 51 System.out.println(myTasks.getTaskStatus("Buy Milk")); // Output: Not Found 52 53 // Add another task and get the count 54 myTasks.addUpdateTask("Clean House", "In Progress"); 55 System.out.println(myTasks.getTaskCount()); // Output: 1 56 } 57}
This example showcases how to leverage Map operations in Java to effectively manage data by adding, updating, retrieving, deleting entries, and checking the number of entries through a simulated TaskManager
application.
Java provides an elegant way to loop through Maps using enhanced for-loops. We can iterate through keys, values, or both simultaneously using the keySet()
, values()
, and entrySet()
methods.
- Keys: To loop through all the keys in the Map, you can use the
keySet
method. - Values: To loop through all the values in the Map, you can use the
values
method. - Entries: To loop through all key-value pairs in the Map, you can use the
entrySet
method.
Let's explore this in our TaskManager
example:
Java1import java.util.HashMap; 2import java.util.Map; 3 4class TaskManager { 5 private Map<String, String> tasks; 6 7 public TaskManager() { 8 tasks = new HashMap<>(); 9 } 10 11 public void addTask(String taskName, String status) { 12 tasks.put(taskName, status); 13 } 14 15 public void printAllTaskKeys() { 16 for (String taskName : tasks.keySet()) { 17 System.out.println(taskName); 18 } 19 } 20 21 public void printAllTaskValues() { 22 for (String status : tasks.values()) { 23 System.out.println(status); 24 } 25 } 26 27 public void printAllEntries() { 28 for (Map.Entry<String, String> entry : tasks.entrySet()) { 29 System.out.println(entry.getKey() + ": " + entry.getValue()); 30 } 31 } 32} 33 34public class Solution { 35 public static void main(String[] args) { 36 TaskManager myTasks = new TaskManager(); 37 myTasks.addTask("Buy Milk", "Pending"); 38 myTasks.addTask("Pay Bills", "Completed"); 39 40 myTasks.printAllTaskKeys(); 41 /* Output: 42 Buy Milk 43 Pay Bills 44 */ 45 46 myTasks.printAllTaskValues(); 47 /* Output: 48 Pending 49 Completed 50 */ 51 52 myTasks.printAllEntries(); 53 /* Output: 54 Buy Milk: Pending 55 Pay Bills: Completed 56 */ 57 } 58}
In this example, we use enhanced for-loops to iterate over a map's keys, values, and entries using the keySet
, values
, and entrySet
methods, allowing us to easily print all tasks in our task manager along with their statuses.
Note: The order of the output can differ, as we are using a HashMap
, which does not maintain insertion order. If maintaining insertion order is important, consider using a LinkedHashMap
instead.
Nesting in Maps involves storing Maps within another Map. It's useful when associating multiple pieces of information with a key. Let's see how this works in a StudentDatabase
example.
Java1import java.util.HashMap; 2import java.util.Map; 3 4class StudentDatabase { 5 private Map<String, Map<String, String>> students; 6 7 public StudentDatabase() { 8 students = new HashMap<>(); 9 } 10 11 public void addStudent(String name, Map<String, String> subjects) { 12 students.put(name, subjects); 13 } 14 15 public String getMark(String name, String subject) { 16 Map<String, String> subjects = students.get(name); 17 if (subjects != null) { 18 return subjects.getOrDefault(subject, "N/A"); 19 } 20 return "N/A"; 21 } 22 23 public void printDatabase() { 24 for (Map.Entry<String, Map<String, String>> student : students.entrySet()) { 25 System.out.println("Student: " + student.getKey()); 26 for (Map.Entry<String, String> subject : student.getValue().entrySet()) { 27 System.out.println(" Subject: " + subject.getKey() + ", Grade: " + subject.getValue()); 28 } 29 } 30 } 31} 32 33public class Solution { 34 public static void main(String[] args) { 35 StudentDatabase studentDb = new StudentDatabase(); 36 Map<String, String> aliceSubjects = new HashMap<>(); 37 aliceSubjects.put("Math", "A"); 38 aliceSubjects.put("English", "B"); 39 studentDb.addStudent("Alice", aliceSubjects); 40 41 System.out.println(studentDb.getMark("Alice", "English")); // Output: "B" 42 System.out.println(studentDb.getMark("Alice", "History")); // Output: "N/A" 43 studentDb.printDatabase(); 44 /* Output: 45 Student: Alice 46 Subject: Math, Grade: A 47 Subject: English, Grade: B 48 */ 49 } 50}
Let's shift our focus to a more interactive and familiar scenario: managing a shopping cart in an online store. This hands-on example will demonstrate how Maps can be used to map product names to their quantities in a shopping cart. You will learn how to add products, update quantities, and retrieve the total number of items in the cart.
Here’s how you can implement and manipulate a shopping cart using a Java Map:
Java1import java.util.HashMap; 2import java.util.Map; 3 4class ShoppingCart { 5 private Map<String, Integer> cart; 6 7 public ShoppingCart() { 8 cart = new HashMap<>(); 9 } 10 11 public void addProduct(String productName, int quantity) { 12 cart.put(productName, cart.getOrDefault(productName, 0) + quantity); 13 } 14 15 public void removeProduct(String productName) { 16 if (cart.containsKey(productName)) { 17 cart.remove(productName); 18 } else { 19 System.out.println(productName + " not found in your cart."); 20 } 21 } 22 23 public void showCart() { 24 if (cart.isEmpty()) { 25 System.out.println("Your shopping cart is empty."); 26 } else { 27 for (Map.Entry<String, Integer> entry : cart.entrySet()) { 28 System.out.println(entry.getKey() + ": " + entry.getValue()); 29 } 30 } 31 } 32} 33 34public class Solution { 35 public static void main(String[] args) { 36 ShoppingCart myCart = new ShoppingCart(); 37 38 myCart.addProduct("Apples", 5); 39 myCart.addProduct("Bananas", 2); 40 myCart.addProduct("Apples", 3); 41 42 myCart.showCart(); 43 /* Output: 44 Apples: 8 45 Bananas: 2 46 */ 47 48 myCart.removeProduct("Bananas"); 49 myCart.showCart(); 50 /* Output: 51 Apples: 8 52 */ 53 } 54}
This example showcases the practical application of Maps to manage a dynamic dataset, such as an online shopping cart. By using product names as keys and their quantities as values, we achieve efficient and flexible data manipulation. This exercise provides a solid foundation for understanding how to handle complex data structures in real-world Java applications.
Well done! Today, we delved into Java Maps and explored various operations on Maps. We now invite you to get hands-on experience with the upcoming practice exercises. To master these concepts and hone your Java HashMap
skills, practice is key. Happy learning!