Java Map Collection Tutorial and Examples
- Details
- Written by Nam Ha Minh
- Last Updated on 18 July 2024   |   Print Email
This tutorial helps you understand and master Map - a member in the Java Collections Framework. You will learn about:
- What are Map and its characteristics?
- Why and When Use Maps?
- 3 implementations of Map in the Java Collections Framework: HashMap, TreeMap and LinkedHashMap
- How to create Maps
- How to perform basic operations on a Map
- How to iterate over a Map (using Collection views)
- How to perform bulk operations with Maps
- How to make a Map collection thread-safe
1. Overview of Map Collection
A Map is an object that maps keys to values, or is a collection of attribute-value pairs. It models the function abstraction in mathematics. The following picture illustrates a map:
Note that a Map is not considered to be a true collection, as the Map interface does not extend the Collection interface. Instead, it starts an independent branch in the Java Collections Framework, as shown in the following diagram:
Characteristics of a Map:
Because a Map is not a true collection, its characteristics and behaviors are different than the other collections like List or Set.
A Map cannot contain duplicate keys and each key can map to at most one value. Some implementations allow null key and null value (HashMap and LinkedHashMap) but some does not (TreeMap).
The order of a map depends on specific implementations, e.g TreeMap and LinkedHashMap have predictable order, while HashMap does not.
Why and When Use Maps:
Maps are perfectly for key-value association mapping such as dictionaries. Use Maps when you want to retrieve and update elements by keys, or perform lookups by keys. Some examples:
- A map of error codes and their descriptions.
- A map of zip codes and cities.
- A map of managers and employees. Each manager (key) is associated with a list of employees (value) he manages.
- A map of classes and students. Each class (key) is associated with a list of students (value).
This tutorial provides code examples around the three major implementations of Map which are described below.
2. Implementations of Map
In the inheritance tree of the Map interface, there are several implementations but only 3 major, common, and general purpose implementations - they are HashMap and LinkedHashMap and TreeMap. Let’s see the characteristics and behaviors of each implementation:
- HashMap: this implementation uses a hash table as the underlying data structure. It implements all of the Map operations and allows null values and one null key. This class is roughly equivalent to Hashtable - a legacy data structure before Java Collections Framework, but it is not synchronized and permits nulls. HashMap does not guarantee the order of its key-value elements. Therefore, consider to use a HashMap when order does not matter and nulls are acceptable.
- LinkedHashMap: this implementation uses a hash table and a linked list as the underlying data structures, thus the order of a LinkedHashMap is predictable, with insertion-order as the default order. This implementation also allows nulls like HashMap. So consider using a LinkedHashMap when you want a Map with its key-value pairs are sorted by their insertion order.
- TreeMap: this implementation uses a red-black tree as the underlying data structure. A TreeMap is sorted according to the natural ordering of its keys, or by a Comparator provided at creation time. This implementation does not allow nulls. So consider using a TreeMap when you want a Map sorts its key-value pairs by the natural order of the keys (e.g. alphabetic order or numeric order), or by a custom order you specify.
So far you have understood the key differences of the 3 major Map’s implementations. And the code examples in this tutorial are around them.
Now, let’s see how to use Map for your daily coding.
3. Creating a new Map
Creating a HashMap:
Always use interface type (Map), generics and diamond operator to declare a new map. The following code creates a HashMap:
Map<Integer, String> mapHttpErrors = new HashMap<>(); mapHttpErrors.put(200, "OK"); mapHttpErrors.put(303, "See Other"); mapHttpErrors.put(404, "Not Found"); mapHttpErrors.put(500, "Internal Server Error"); System.out.println(mapHttpErrors);
This maps HTTP status codes to their descriptions. Output:
{404=Not Found, 500=Internal Server Error, 200=OK, 303=See Other}
As you can see in the output, a HashMap does not impose any order on its key-value elements.
You can create a new Map that copies elements from an existing map. For example:
Map<Integer, String> mapErrors = new HashMap<>(mapHttpErrors);
The map mapErrors is created with initial elements copied from the map mapHttpErrors.
Creating a LinkedHashMap:
The following code creates a LinkedHashMap that maps phone numbers with contact names:
Map<String, String> mapContacts = new LinkedHashMap<>(); mapContacts.put("0169238175", "Tom"); mapContacts.put("0904891321", "Peter"); mapContacts.put("0945678912", "Mary"); mapContacts.put("0981127421", "John"); System.out.println(mapContacts);
Output:
{0169238175=Tom, 0904891321=Peter, 0945678912=Mary, 0981127421=John}
As you can see, the LinkedHashMap maintains its elements by their insertion order.
Creating a TreeMap:
The following code creates a TreeMap that maps file extensions to programming languages:
Map<String, String> mapLang = new TreeMap<>(); mapLang.put(".c", "C"); mapLang.put(".java", "Java"); mapLang.put(".pl", "Perl"); mapLang.put(".cs", "C#"); mapLang.put(".php", "PHP"); mapLang.put(".cpp", "C++"); mapLang.put(".xml", "XML"); System.out.println(mapLang);
Output:
{.c=C, .cpp=C++, .cs=C#, .java=Java, .php=PHP, .pl=Perl, .xml=XML}
As you can see, the TreeMap sorts its keys by their natural ordering, which is the alphabetical order in this case.
You can also create a Map with key-value pairs initialized in just a single line, as described in this article.
4. Performing Basic Operations on a Map
The basic operations of a Map are association (put), lookup (get), checking (containsKeyand containsValue), modification (removeand replace) and cardinality (size and isEmpty).
Associating a value with a key:
The put(K, V) method associates the specified value V with the specified key K. If the map already contains a mapping for the key, the old value is replaced by the specified value:
Map<Integer, String> mapHttpErrors = new HashMap<>(); mapHttpErrors.put(400, "Bad Request"); mapHttpErrors.put(304, "Not Modified"); mapHttpErrors.put(200, "OK"); mapHttpErrors.put(301, "Moved Permanently"); mapHttpErrors.put(500, "Internal Server Error");
Getting a value associated with a specified key:
The get(Object key) method returns the value associated with the specified key, or returns null if the map contains no mapping for the key. Given the map in the previous example:
String status301 = mapHttpErrors.get(301); System.out.println("301: " + status301);
Output:
301: Moved Permanently
Checking if the map contains a specified key:
The method containsKey(Object key) returns true if the map contains a mapping for the specified key. For example:
if (mapHttpErrors.containsKey("200")) { System.out.println("Http status 200"); }
Output:
Found: Http status 200
Checking if the map contains a specified value:
The method containsValue(Object value) returns true if the map contains one or more keys associated with the specified value. For example:
if (mapHttpErrors.containsValue("OK")) { System.out.println("Found status OK"); }
Output:
Found status OK
Removing a mapping from the map:
The remove(Object key) method removes the mapping for a key from the map if it is present (we care about only the key, and the value does not matter). This method returns the value to which the map previously associated the key, or null if the map doesn’t contain mapping for the key. Here’s an example:
String removedValue = mapHttpErrors.remove(500); if (removedValue != null) { System.out.println("Removed value: " + removedValue); }
Output:
Removed value: Internal Server Error
Similarly, the remove(Object key, Object value) method removes the mapping of a specified key and specified value, and returns true if the value was removed. This method is useful in case we really care about the key and value to be removed.
I recommend you to read this well-know Java collection book to learn in-depth about Java collections framework.
Replacing a value associated with a specified key:
The replace(K key, V value)method replaces the entry for the specified key only if it is currently mapping to some value. This method returns the previous value associated with the specified key. Here’s an example:
System.out.println("Map before: " + mapHttpErrors); mapHttpErrors.replace(304, "No Changes"); System.out.println("Map after: " + mapHttpErrors);
Output:
Map before: {400=Bad Request, 304=Not Modified, 200=OK, 301=Moved Permanently} Map after: {400=Bad Request, 304=No Changes, 200=OK, 301=Moved Permanently}
Similarly, the replace(K key, V oldValue, V newValue) method replaces the entry for the specified key only if it is currently mapping to the specified value. This method returns true if the value was replaced. Useful in case we want to replace exactly a key-value mapping.
Getting the size of the map:
The size()method returns the number of key-value mappings in this map. For example:
int size = mapHttpErrors.size();
Output:
Number of HTTP status code: 5
Checking if the map is empty:
The isEmpty() method returns true if the map contains no key-value mappings. For example:
if (mapHttpErrors.isEmpty()) { System.out.println("No Error"); } else { System.out.println("Have HTTP Errors"); }
Output:
Have HTTP Errors
5. Iterating Over a Map (using Collection views)
As a Map is not a true collection, there is no direct method for iterating over a map. Instead, we can iterate over a map using its collection views. Any Map’s implementation has to provide the following three Collection view methods:
- keySet(): returns a Set view of the keys contained in the map. Hence we can iterate over the keys of the map as shown in the following example:
Map<String, String> mapCountryCodes = new HashMap<>(); mapCountryCodes.put("1", "USA"); mapCountryCodes.put("44", "United Kingdom"); mapCountryCodes.put("33", "France"); mapCountryCodes.put("81", "Japan"); Set<String> setCodes = mapCountryCodes.keySet(); Iterator<String> iterator = setCodes.iterator(); while (iterator.hasNext()) { String code = iterator.next(); String country = mapCountryCodes.get(code); System.out.println(code + " => " + country); }
Output:44 => United Kingdom 33 => France 1 => USA 81 => Japan
- values(): returns a collection of values contained in the map. Thus we can iterate over values of the map like this:
Collection<String> countries = mapCountryCodes.values(); for (String country : countries) { System.out.println(country); }
Output:United Kingdom France USA Japan
- entrySet(): returns a Set view of the mappings contained in this map. Therefore we can iterate over mappings in the map like this:
Set<Map.Entry<String, String>> entries = mapCountryCodes.entrySet(); for (Map.Entry<String, String> entry : entries) { String code = entry.getKey(); String country = entry.getValue(); System.out.println(code + " => " + country); }
Output:
44 => United Kingdom 33 => France 1 => USA 81 => Japan
Since Java 8 with Lambda expressions and the forEach() statement, iterating over a Map is as easy as:
mapCountryCodes.forEach( (code, country) -> System.out.println(code + " => " + country));
Output:
44 => United Kingdom 33 => France 1 => USA 81 => Japan
For more information about the different methods of collection iteration, read this article: The 4 Methods for Iterating Collections in Java.
6. Performing Bulk Operations with Maps
There are two bulk operations with maps: clear() and putAll().
The clear() method removes all mappings from the map. The map will be empty after this method returns. For example:
mapHttpErrors.clear(); System.out.println("Is map empty? " + mapHttpErrors.isEmpty());
Output:
Is map empty? true
The putAll(Map<K, V> m) method copies all of the mappings from the specified map to this map. Here’s an example:
Map<Integer, String> countryCodesEU = new HashMap<>(); countryCodesEU.put(44, "United Kingdom"); countryCodesEU.put(33, "France"); countryCodesEU.put(49, "Germany"); Map<Integer, String> countryCodesWorld = new HashMap<>(); countryCodesWorld.put(1, "United States"); countryCodesWorld.put(86, "China"); countryCodesWorld.put(82, "South Korea"); System.out.println("Before: " + countryCodesWorld); countryCodesWorld.putAll(countryCodesEU); System.out.println("After: " + countryCodesWorld);
Output:
Before: {1=United States, 82=South Korea, 86=China} After: {1=United States, 33=France, 49=Germany, 82=South Korea, 86=China, 44=United Kingdom}
7. Concurrent Maps
Unlike the legacy Hashtable which is synchronized, the HashMap, TreeMap and LinkedHashMap are not synchronized. If thread-safe is priority, consider using ConcurrentHashMap in place of HashMap. Or we can use the Collections.synchronizedMap() utility method that returns a synchronized (thread-safe) map backed by the specified map. For example:
Map<Integer, String> map = Collections.synchronizedMap(new HashMap<>());
And remember we have to manually synchronize the map when iterating over any of its collection views:
Set<Integer> keySet = map.keySet(); synchronized (map) { Iterator<Integer> iterator = keySet.iterator(); while (iterator.hasNext()) { Integer key = iterator.next(); String value = map.get(key); } }
If you use a kind of SortedMap, e.g. TreeMap, consider using the more specific method Collections.synchronizedSortedMap().
NOTE: If you use your own type for the key and value (e.g. Student or Employee), the key class and value class must implement the equals() and hashCode() methods properly so that the map can look up them correctly.
API References
- The Map Interface (The Java Tutorials)
- Map interface Javadoc
- HashMap class Javadoc
- LinkedHashMap class Javadoc
- TreeMap class Javadoc
Related Map Tutorials:
- Java NavigableMap and TreeMap Tutorial and Examples
- Java SortedMap and TreeMap Tutorial and Examples
- Class diagram of Map API
Other Java Collections Tutorials:
- Java Set Collection Tutorial and Examples
- Java List Collection Tutorial and Examples
- Java Queue Collection Tutorial and Examples
- 18 Java Collections and Generics Best Practices
That's a comprehensive and great detailed tutorial about Java map. I hope you grasp something new and enjoy learning. If you have time and budget, I recommend you to take this Java masterclass course to learn Java programming in-depth.
Comments
HashMap map
a method updateRecord()
I guess,string "200" need to be replaced with Integer 200 to gt the desired output "Found: Http status 200"
if (mapHttpErrors.containsKey(200)) {
if (mapHttpErrors.containsKey("200")) {
System.out.println("Http status 200");
}