avatarLincoln W Daniel

Summary

The provided web content discusses the use and importance of Java's HashMap, detailing how it allows for the storage and retrieval of key-value pairs with unique keys, and its practical application in creating a dictionary-like structure.

Abstract

Java's HashMap is a versatile data structure that stores elements as key-value pairs, ensuring that each key is unique. It is particularly useful for scenarios such as creating a dictionary where quick retrieval of values based on keys is essential. The HashMap internally uses arrays to store its elements and provides methods for adding, updating, and removing pairs, as well as checking for the existence of keys. While keys and values can be of any datatype, specifying the types of keys and values is recommended for clarity and to avoid ambiguity. The content also demonstrates how to initialize a HashMap, add pairs to it, retrieve values, and update or remove pairs, emphasizing best practices such as using the replace() method for updating existing pairs and checking for key existence before updating values.

Opinions

  • The author emphasizes the power and utility of HashMaps in Java, suggesting they are a superior choice for key-value pair storage over arrays and lists when unique keys are required.
  • It is noted that while Java's HashMap can handle any datatype for keys and values, it is preferable to specify the data types for keys and values to prevent unexpected behavior due to ambiguity.
  • The author advocates for the use of the replace() method over put() when updating the value of an existing key to avoid unintended additions to the map.
  • The importance of encapsulation is highlighted, as the internal workings of a HashMap, such as hashing of keys, are abstracted away from the user.
  • The author suggests that using a HashMap to create a study guide could be an effective educational tool, implying that practical applications of programming concepts can enhance learning.

Arrays let you collect a fixed amount of elements in one data structure, and Lists can do the same but without bounds. The only thing they both don’t allow you to do is store objects and retrieve them by a specific, unique key. This is where the HashMap comes into play. If we want to make a dictionary of all the words in the English language alongside their meanings, our best bet would be to use a HashMap.

Why HashMaps are Important & Useful

Maps in Java are powerful tools, and the HashMap is perhaps one of the most powerful of them all. The HashMap class, an implementation of the Map interface, takes the best ideas of the List interface, combines it with the prowess of arrays, and gives us a tool to collect key-value pairs in one place. Elements of a HashMap are stored as pairs and it insures that no two pairs can have the same key, therefore maintaining the unique property of each of element.

The HashMap class provided to us by Java allows us to collect values of the same type and store them with unique keys. In the background, a HashMap uses arrays to store its elements. However, we don’t care about how it works in the background because all of the hard work is encapsulated. The HashMap class provides us methods to put a pair in the map, replace a pair’s value by key, remove a pair by key, check for the existence of a key, and clear the map like we do with a list.

A key can be of any datatype, but its important to remember that String keys are case sensitive. To ensure that all keys in the HashMap are unique, the map has a hash() method behind the scenes to hash all keys added to it. When you call the put() instance method, the key you provide is hashed to a unique hash string value and when you call the get() or containsKey() instance methods, the key you provide is hashed the same way. The hash that results is used to find a pair in the map that has a key with a matching hash. If a pair is found, the pair will be returned if you called get(), a boolean value of true will be returned if you called containsKey(), or its value will be updated with the new value if you called put(). Let’s try to make a dictionary of some of our favorite Java terms to help us study later:

HashMap dictionary = new HashMap();
dictionary.put("Variable", "Used to store a single value for later use.");
dictionary.put("String", "A class for representing character strings.");
dictionary.put("double", "A primitive datatype for representing floating point numbers.");
dictionary.put("Double", "A class for wrapping a double in an Object with convenient methods.");
dictionary.put(0, "The number zero. The first index in arrays and the first position on lists.");
dictionary.put("zero", 0);
System.out.println("Elements in map: " + dictionary.size());
//prints "Elements in map: 6"

We’ve added six pairs to our dictionary HashMap instance — five String keys and one integer key. Let’s print out the value of some of the pairs by key:

System.out.println("double: " + dictionary.get("double"));
Object meaningOfDouble = dictionary.get("Double");
Object meaningOf0 = dictionary.get(0);
System.out.println("Double: " + meaningOfDouble);
System.out.println("0: " + meaningOf0);
System.out.println("zero: " + dictionary.get("zero"));
/*Prints
    double: A primitive datatype for representing floating point numbers.
    Double: A class for wrapping a double in an Object with convenient methods.
    0: The number zero. The first index in arrays and the first position on lists.
    zero: 0
 */

Notice that when we retrieved the value of the elements of our dictionary, they were returned as instances of the Object class. This is because if we do not specify which type of data our keys and values can be, Java makes Object the type of the HashMap’s keys and values because every class is a subclass of the Object class; the Integer, Double, Long, and other wrapper classes are provided by Java to wrap primitive datatypes in objects because primitives are not objects. This is why we were able to have both String and int keys and values. This is okay sometimes, but we should usually specify exactly what type of data we want to store in our data structures to avoid unexpected situations that can result from ambiguity. To specify the type of our map, we do the same thing we did to initialize our LinkedList instance in the LinkedLists chapter: place the type’s class name inside of a set of opening and closing arrows <>. We could make our HashMap instance accept, String keys and Integer values, but doesn’t make much sense for our dictionary .Let’s remake our dictionary to only accept String keys and String values:

HashMap<String, String> stringDictionary = new HashMap<>();
stringDictionary.put("Class", "A template for creating objects.");
stringDictionary.put("Object", "An instance of a class.");

We now have a dictionary that stores pairs of String keys and String values and it has the definition of a Java “Class” and “Object”. The “Class” definition seems a little unhelpful, so let’s update it:

stringDictionary.replace("Class", "A template that defines the attributes and behavior that objects constructed from it can exhibit.");

Instead of calling the put() method again to change the value of the “Class” key in our map, we called the replace() instance method. Calling replace() ensures that the pair will not be added to the map if the key was not already present in the map. If we had called put() instead, the pair would have been added to the map even though we only intended to update the value of the pair. For that reason, you should use replace() to update the value of a pair with a key you know exists in a HashMap and use put() if you want to update the value of a pair with a key you wouldn’t mind adding to your map if it doesn’t already exist. The best of both world, often the better design pattern, would be to check if the key exists in our map before we replace it:

if(stringDictionary.containsKey("Class")) {
    stringDictionary.replace("Class", "A better definition.");
} else {
    stringDictionary.put("Class", "A descriptive definition");
}

String meaningOfClass = stringDictionary.get("Class");
System.out.println("Class: " + meaningOfClass);
//prints "Class: A better definition."

In that code snippet, we replaced the value of the pair if the key already existed in the map and we added the pair to the map otherwise by checking with containsKey(). If we want to remove a pair from our map, we don’t have to make sure it exists first. We can simply ask the map to remove the pair with a key matching the key we provide as an argument to the remove() method. If the key exists in the map, the corresponding value will be removed return, and otherwise, nothing will be removed and returned:

String valueOfRemovedPair = stringDictionary.remove("Class");
System.out.println("Value of removed 'Class': " + valueOfRemovedPair);
//prints "Value of removed pair with key 'Class': A better definition."

The only thing left to do is clear our dictionary and start over. If we no longer need the pairs in our HashMap, we can remove all of them at once by calling the clear() method:

stringDictionary.clear();
System.out.println("Pairs in our string dictionary: " + stringDictionary.size());
//prints "Pairs in our string dictionary: 0"

Our stringDictionary HashMap is now empty and you are free to add new pairs to it and use it to study up on everything you have learned about Java so far. You could make a study guide by adding each concept to the HashMap along with its meaning, iterate over the map’s keys with Java’s handy iterator method which you can learn about by doing some research on Google, and try to guess the corresponding value of each key before you print it to the console. I’ll get you started in the supporting code.

Next Chapter

Table of Contents

Programming
Coding
Java
Recommended from ReadMedium
avatarLeed Software Development
Best Sites for Java Coding Practice

Introduction:

2 min read