This tutorial helps you understand and master Map - a member in the Java Collections Framework. You will learn about:

 

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:

Map function abstraction

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:

collections framework overview 

 

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:

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:

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.

 

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:

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

 

Related Map Tutorials:

 

Other Java Collections Tutorials:

 

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.

 


About the Author:

is certified Java programmer (SCJP and SCWCD). He started programming with Java in the time of Java 1.4 and has been falling in love with Java since then. Make friend with him on Facebook and watch his Java videos you YouTube.