Course Content
Java Data Structures
Java Data Structures
What is Map?
Finally, we've moved on to truly complex and intriguing data structures. Today, we'll discuss the Map
interface in Java. The Map
interface is part of the Java Collections framework and defines methods for working with data in the form of key-value pairs.
Let's take a look at the definition:
The primary implementation of such a data structure in Java
is HashMap
, which implements the Map
interface. Let's explore the main methods and the operating principles of this implementation.
We'll start with the declaration and methods:
main
Map<K, V> map = new HashMap<>();
Here, we see that in the generics or diamond brackets, two values are specified:
- The value
K
corresponds to the data type of the key; - The value
V
corresponds to the data type of the value.
Thus, when declaring this data structure, we indicate the data types of our key-value values.
Now, let's examine the methods defined in the Map
interface:
V put(K key, V value)
:- Associates the specified value with the specified key in this map. If the map previously contained a mapping for the key, the old value is replaced.
Note
In the case of using
HashMap<>()
, when inserting multiple values with the same key, a collision occurs. We will delve into the working principle ofHashMap
later in this section.
main
package com.example; import java.util.HashMap; import java.util.Map; public class Main { public static void main(String[] args) { Map<Integer, String> map = new HashMap<>(); map.put(1, "One"); map.put(2, "Two"); map.put(3, "Three"); System.out.println(map); } }
V get(Object key)
:- Returns the value to which the specified key is mapped, or
null
if this map contains no mapping for the key.
- Returns the value to which the specified key is mapped, or
This is where we specify the key to retrieve the corresponding value.
Let's retrieve the value with key 2:
main
package com.example; import java.util.HashMap; import java.util.Map; public class Main { public static void main(String[] args) { Map<Integer, String> map = new HashMap<>(); map.put(1, "One"); map.put(2, "Two"); map.put(3, "Three"); System.out.println("Map: " + map); String value = map.get(2); System.out.println("Value: " + value); } }
boolean containsKey(Object key)
:- Returns
true
if the map contains a mapping for the specified key.
- Returns
boolean containsValue(Object value)
:- Returns
true
if the map contains one or more keys mapped to the specified value.
- Returns
These two methods are obviously related, and they help determine whether the specified map contains the desired keys or values. These methods are convenient to use as conditions since they return boolean
values.
Let's look at an example:
main
package com.example; import java.util.HashMap; import java.util.Map; public class Main { public static void main(String[] args) { Map<Integer, String> map = new HashMap<>(); map.put(1, "One"); map.put(2, "Two"); map.put(3, "Three"); System.out.println("Map: " + map); if (map.containsKey(2)) { System.out.println("Value with key 2: " + map.get(2)); } else { System.out.println("There is no value with key 2!"); } if (map.containsValue("Four")) { System.out.println(map.get(4)); } else { System.out.println("There is no key with value \"Four\"!"); } } }
In the example above, we check for the presence of a key and the presence of a value in the map. If values are found, we display them on the console. If there are no such values, we output messages indicating the absence of such data.
boolean isEmpty()
:- Returns
true
if this map contains no key-value mappings.
- Returns
V remove(Object key)
:- Removes the mapping for the specified key from this map if present and returns the previous value.
Just like in other data structures, we can remove elements from the map.
Note
When using
HashMap
, all values under one key will be removed. We will delve into this in more detail later in this section.
main
package com.example; import java.util.HashMap; import java.util.Map; public class Main { public static void main(String[] args) { Map<Integer, String> map = new HashMap<>(); map.put(1, "One"); map.put(2, "Two"); map.put(3, "Three"); System.out.println("Map: " + map); String removedElement = map.remove(3); System.out.println("Removed value: " + removedElement + ".\nMap after the removal operation: " + map); } }
Thus, we can remove elements by key.
Next, there are methods you are already familiar with, which I will list without examples. But there are also interesting methods left.
Let's start with the basics:
void clear()
:- Removes all elements from the map.
int size()
:- Returns the number of key-value mappings in this map.
void putAll(Map<? extends K, ? extends V> m)
:- Copies all of the mappings from the specified map to this map.
Now, let's move on to the methods that return a collection with values(or keys) from the map. In other words, we retrieve from the data structure a key-value structure that stores only values(or keys).
For example, ArrayList<>
.
main
package com.example; import java.util.*; public class Main { public static void main(String[] args) { Map<Integer, String> map = new HashMap<>(); map.put(1, "One"); map.put(2, "Two"); map.put(3, "Three"); System.out.println("Map: " + map); Collection<String> list; list = map.values(); System.out.println("Values" + list); } }
Here, we obtained a collection of values from the map.
Now, we can transfer this collection to an ArrayList
:
main
package com.example; import java.util.*; public class Main { public static void main(String[] args) { Map<Integer, String> map = new HashMap<>(); map.put(1, "One"); map.put(2, "Two"); map.put(3, "Three"); System.out.println("Map: " + map); Collection<String> collection; collection = map.values(); System.out.println("Values" + collection); List<String> arrayList = new ArrayList<>(collection); System.out.println("ArrayList: " + arrayList); } }
We initialized an ArrayList
using values from the map.
There is also a method that returns keys from the map. However, these keys will be returned in the form of a structure called a Set
. We won't delve into this data structure now; it's worth mentioning that a Set
is a data structure that contains exclusively unique values.
Let's look at this method:
Set<K> keySet()
:- Returns a
Set
view of the keys contained in this map.
- Returns a
main
package com.example; import java.util.*; public class Main { public static void main(String[] args) { Map<Integer, String> map = new HashMap<>(); map.put(1, "One"); map.put(2, "Two"); map.put(3, "Three"); System.out.println("Map: " + map); Set<Integer> keys; keys = map.keySet(); System.out.println("Keys: " + keys); } }
Thus, we can also retrieve a set of all keys from the map.
Well, it seems we're done with the methods. Let's now take a look at the usage of the map, as well as practical examples:
Map Usage
A structure like key-value has many practical applications. Let's consider the simplest of these structures: a student grading system.
Let's create a map where the key is of type String
, representing the student's name, and the value is of type Integer
, representing the student's grade. This way, we can assign grades to students and easily retrieve the grade of a specific student using the key:
main
package com.example; import java.util.*; public class Main { public static void main(String[] args) { Map<String, Integer> studentsGrades = new HashMap<>(); studentsGrades.put("Bob", 9); studentsGrades.put("Alice", 8); studentsGrades.put("Mike", 5); studentsGrades.put("John", 10); studentsGrades.put("Martin", 7); studentsGrades.put("Peter", 5); System.out.println("Student's grades: " + studentsGrades); } }
Now, let's imagine we are tasked with retrieving the grades of Mike and Alice, and then comparing them. We can easily accomplish this using the methods we have learned above. Let's implement this in the code:
main
package com.example; import java.util.*; public class Main { public static void main(String[] args) { Map<String, Integer> studentsGrades = new HashMap<>(); studentsGrades.put("Bob", 9); studentsGrades.put("Alice", 8); studentsGrades.put("Mike", 5); studentsGrades.put("John", 10); studentsGrades.put("Martin", 7); studentsGrades.put("Peter", 5); System.out.println("Student's grades: " + studentsGrades); Integer mikeGrade = studentsGrades.get("Mike"); Integer aliceGrade = studentsGrades.get("Alice"); System.out.println(mikeGrade.compareTo(aliceGrade) == -1 ? "Alice's grade is higher": "Mike's grade is higher"); } }
I used the ternary operator and the compareTo() method of the Integer wrapper class. In case you don't understand how it works, it can be explained as follows:
main
package com.example; import java.util.*; public class Main { public static void main(String[] args) { Map<String, Integer> studentsGrades = new HashMap<>(); studentsGrades.put("Bob", 9); studentsGrades.put("Alice", 8); studentsGrades.put("Mike", 5); studentsGrades.put("John", 10); studentsGrades.put("Martin", 7); studentsGrades.put("Peter", 5); System.out.println("Student's grades: " + studentsGrades); Integer mikeGrade = studentsGrades.get("Mike"); Integer aliceGrade = studentsGrades.get("Alice"); if (mikeGrade.compareTo(aliceGrade) == -1) { System.out.println("Alice's grade is higher"); } else { System.out.println("Mike's grade is higher"); } } }
Note
If you think about it, such queries are very similar to SQL queries. If you are familiar with SQL, it will be much easier for you to understand the interaction with different data structures and databases.
Now, let's consider what if we are asked to gather all students with a grade higher than 7 (excluding 7). This becomes interesting, and I will now explain to you how to do it!
Iteration through the map
Iterating over elements in a Map
in Java can be done using various methods provided by the Map
interface and its implementations. Here are several ways to iterate over a Map
:
- Iterating over Keys (
keySet()
):- The
keySet()
method returns a set of all keys in theMap
. You can use this set to iterate over keys and retrieve corresponding values.
- The
main
package com.example; import java.util.*; public class Main { public static void main(String[] args) { Map<String, Integer> map = new HashMap<>(); map.put("Key1", 1); map.put("Key2", 2); for (String key : map.keySet()) { Integer value = map.get(key); System.out.println("Key: " + key + ", Value: " + value); } } }
- Iterating over Values (
values()
):- The
values()
method returns a collection of all values in theMap
. You can use this collection to iterate over values.
- The
main
package com.example; import java.util.*; public class Main { public static void main(String[] args) { Map<String, Integer> map = new HashMap<>(); map.put("Key1", 1); map.put("Key2", 2); for (Integer value : map.values()) { System.out.println("Value: " + value); } } }
- Iterating over Key-Value Pairs (
entrySet()
):- The
entrySet()
method returns a set ofMap.Entry
objects representing key-value pairs. This allows iterating over pairs directly.
- The
main
package com.example; import java.util.*; public class Main { public static void main(String[] args) { Map<String, Integer> map = new HashMap<>(); map.put("Key1", 1); map.put("Key2", 2); for (Map.Entry<String, Integer> entry : map.entrySet()) { String key = entry.getKey(); Integer value = entry.getValue(); System.out.println("Key: " + key + ", Value: " + value); } } }
Let's delve a bit deeper into this. Initially, it might seem insanely complex to understand, but you don't need to get into the details of how it works, as the syntax is always the same:
Using the entry
object, we can simultaneously access both the key and the value in the map. Now, let's solve the task given earlier using the entry set: retrieve all students with a grade higher than 7. For this, we'll use a check through entry.getValue()
, and when we find suitable students, we'll retrieve their keys into a pre-created ArrayList
:
main
package com.example; import java.util.*; public class Main { public static void main(String[] args) { Map<String, Integer> studentsGrades = new HashMap<>(); studentsGrades.put("Bob", 9); studentsGrades.put("Alice", 8); studentsGrades.put("Mike", 5); studentsGrades.put("John", 10); studentsGrades.put("Martin", 7); studentsGrades.put("Peter", 5); System.out.println("Student's grades: " + studentsGrades); List<String> studentsWithGradeHigherThanSeven = new ArrayList<>(); for (Map.Entry<String, Integer> entry : studentsGrades.entrySet()) { if (entry.getValue() > 7) { studentsWithGradeHigherThanSeven.add(entry.getKey()); } } System.out.println(studentsWithGradeHigherThanSeven); } }
Thus, we can iterate through the map and find the desired list of students who passed the exam!
The entry set is a very useful tool as it allows various ways of iterating through the map using a loop, having access to both the key and the value.
In the next chapter, we will delve into how HashMap
, which we used so actively in this chapter, actually works!
Thanks for your feedback!