HashMap in Java
In Java, a HashMap is part of the Collections Framework and implements the Map interface, providing a basic implementation of a map data structure, which stores key-value pairs. It allows for fast retrieval of elements based on keys, with retrieval time aiming to be constant time, O(1). HashMap is based on the hash table data structure. Keys in a HashMap must be unique, and each key maps to exactly one value. The keys and values can be of any type, including null for keys and values. However, HashMap does not maintain any order for its entries, meaning the order of insertion is not preserved, and iterating over a HashMap may produce a different order of elements each time. It is not synchronized and hence, not thread-safe without external synchronization.
Functions of HashMap in Java:
-
put(Key k, Value v):
Adds a key-value pair to the HashMap. If the map previously contained a mapping for the key, the old value is replaced by the specified value.
-
get(Object key):
Returns the value to which the specified key is mapped, or null if this map contains no mapping for the key.
-
remove(Object key):
Removes the mapping for a key from this map if it is present. Returns the value to which this map previously associated the key, or null if the map contained no mapping for the key.
-
containsKey(Object key):
Returns true if this map contains a mapping for the specified key, thereby allowing a quick check of element existence by key.
-
containsValue(Object value):
Checks if the map maps one or more keys to the specified value. Returns true if at least one key maps to this value.
-
keySet():
Returns a Set view of the keys contained in this map. This is useful for iterating over keys of the HashMap.
- values():
Provides a Collection view of the values contained in this map. This is useful for iterating over values or performing bulk operations on the values.
- entrySet():
Returns a Set view of the mappings contained in this map. Each element in this set is a key-value pair represented by Map.Entry. This method is useful for iterating over the key-value pairs of the map.
Example of HashMap in Java:
Here is an example of how to use a HashMap in Java, demonstrating several of the key functions such as adding, removing, and retrieving elements:
import java.util.HashMap;
public class HashMapExample {
public static void main(String[] args) {
// Creating a HashMap to store Integer keys and String values
HashMap<Integer, String> map = new HashMap<>();
// Adding elements to the HashMap
map.put(1, “Apple”);
map.put(2, “Banana”);
map.put(3, “Cherry”);
// Displaying the contents of the HashMap
System.out.println(“Initial map: ” + map);
// Accessing a value using a key
String fruit = map.get(2); // Should return “Banana”
System.out.println(“Value for key 2: ” + fruit);
// Removing an element by key
String removedFruit = map.remove(3); // Should remove “Cherry”
System.out.println(“Removed value: ” + removedFruit);
// Checking if a specific key or value exists in the map
boolean hasKey = map.containsKey(1); // Should return true
boolean hasValue = map.containsValue(“Apple”); // Should return true
System.out.println(“Contains key 1: ” + hasKey);
System.out.println(“Contains value ‘Apple’: ” + hasValue);
// Iterating over keys
System.out.println(“Keys in map:”);
for (Integer key : map.keySet()) {
System.out.println(key);
}
// Iterating over values
System.out.println(“Values in map:”);
for (String value : map.values()) {
System.out.println(value);
}
// Iterating over key-value pairs
System.out.println(“Entries in map:”);
for (HashMap.Entry<Integer, String> entry : map.entrySet()) {
System.out.println(“Key: ” + entry.getKey() + “, Value: ” + entry.getValue());
}
}
}
Explanation of the Code:
-
Creation and Initialization:
HashMap named map is created to store keys of type Integer and values of type String.
-
Adding Elements:
Entries are added to the map using put(key, value).
-
Accessing Elements:
get(key) method retrieves the value associated with a specific key.
-
Removing Elements:
remove(key) method removes the entry associated with a specific key and returns the value that was removed.
-
Existence Check:
containsKey(key) and containsValue(value) methods check whether a specific key or value is present in the map.
-
Iterating over Elements:
Using keySet(), values(), and entrySet() to iterate over keys, values, and entries, respectively.
LinkedHashMap in Java
In Java, a LinkedHashMap extends HashMap and maintains a doubly-linked list across its entries. This linked list preserves the insertion order of the entries, meaning elements will be iterated in the order they were added to the map, regardless of their hash values. If access order is enabled via a constructor parameter, the iteration reflects the order in which keys were last accessed, from least-recently accessed to most-recently. Like HashMap, LinkedHashMap allows for constant-time performance for basic operations such as adding, removing, and accessing elements. It accepts null values and null keys just like HashMap. LinkedHashMap is ideal for creating cache data structures where maintaining order is necessary. It is also not synchronized and requires external synchronization if used by concurrent threads.
Functions of LinkedHashMap in Java:
-
Constructor Variants:
LinkedHashMap can be instantiated with optional arguments that define the initial capacity, load factor, and access order (true for access-order, false for insertion-order), allowing for customized behavior based on specific needs.
-
put(Key k, Value v):
Adds a key-value pair to the LinkedHashMap. If the map previously contained a mapping for the key, the old value is replaced. This operation maintains the insertion or access order based on the constructor settings.
-
get(Object key):
Returns the value to which the specified key is mapped, or null if this map contains no mapping for the key. Accessing a value might affect the iteration order if the access order is set to true.
-
remove(Object key):
Removes the specified key’s mapping from the map if present, and returns the value associated with the key. This operation also maintains the order.
-
containsKey(Object key):
Checks if the map contains a mapping for the specified key, without modifying the access order.
-
containsValue(Object value):
Determines whether the map contains one or more keys to the specified value, operating similarly to HashMap but also maintaining order.
- clear():
Removes all of the mappings from this map. The map will be empty after this call returns, and the order is reset.
-
entrySet(), keySet(), and values():
Each of these methods returns a set or collection view of the map’s contents (entries, keys, and values respectively), which reflect the order in which elements were added to the map or accessed, based on the LinkedHashMap‘s configuration.
Example of LinkedHashMap in Java:
This example highlights how LinkedHashMap maintains the insertion order of the entries, which is particularly useful when the order of elements needs to be consistent over iterations.
import java.util.LinkedHashMap;
import java.util.Map;
public class LinkedHashMapExample {
public static void main(String[] args) {
// Creating a LinkedHashMap
LinkedHashMap<Integer, String> lhm = new LinkedHashMap<>();
// Adding elements to the LinkedHashMap
lhm.put(100, “Apple”);
lhm.put(101, “Banana”);
lhm.put(102, “Cherry”);
// Display the content in the map
System.out.println(“Contents of LinkedHashMap : ” + lhm);
// Getting a value from the LinkedHashMap
String value = lhm.get(101);
System.out.println(“Value at key 101: ” + value);
// Removing an entry from the LinkedHashMap
lhm.remove(100);
System.out.println(“Contents of LinkedHashMap after removal: ” + lhm);
// Iterating over the LinkedHashMap’s entry set
System.out.println(“Entries in LinkedHashMap:”);
for (Map.Entry<Integer, String> entry : lhm.entrySet()) {
System.out.println(entry.getKey() + ” => ” + entry.getValue());
}
}
}
Explanation of the Code:
-
Creation and Initialization:
LinkedHashMap named lhm is created to store keys of type Integer and values of type String.
-
Adding Elements:
put(key, value) method is used to add elements to the LinkedHashMap. The insertion order is maintained.
-
Accessing and Removing Elements:
get(key) method retrieves the value for a specific key, and the remove(key) method deletes an entry from the map.
- Iterating:
The map is iterated using the entrySet() method, which provides a set of all the entries (key-value pairs) in the map, maintaining the order of insertion.
Key differences between HashMap and LinkedHashMap in Java
Aspect | HashMap | LinkedHashMap |
Ordering | No order preserved | Insertion order preserved |
Overhead | Less overhead | More overhead (linked list) |
Iteration Speed | Faster iteration on keys | Slower due to order maintenance |
Usage | When order isn’t necessary | When maintaining order is crucial |
Memory Usage | Lower memory usage | Higher due to link maintenance |
Access Order | No access order option | Access order can be set |
Insertion | Insert is usually faster | Insert is slightly slower |
Retrieval Speed | Fast key access | Slightly slower due to ordering |
Null Keys/Values | Allows null keys and values | Allows null keys and values |
Implementation | Direct table indexing | Maintains a double-linked list |
Constructor Variants | Fewer options | Offers order as a parameter |
Use in Caching | Less commonly used in caching | Frequently used in LRU caches |
Deletion Performance | Fast deletes | Deletes are slower |
Head Element Access | Not applicable | Can access first/last easily |
Complexity of Code | Simpler implementation | More complex due to links |
Key Similarities between HashMap and LinkedHashMap in Java
-
Extends AbstractMap:
Both HashMap and LinkedHashMap extend Java’s AbstractMap class and implement the Map interface, which provides them with standard map functionalities.
-
Key-Value Storage:
Both classes store elements in key-value pairs, making them suitable for scenarios where data needs to be accessed quickly by keys.
-
Hash Table Based:
Both HashMap and LinkedHashMap use hashing for storing and retrieving elements, which ensures that the complexity of basic operations like get() and put() remains constant time on average.
-
Allows Null Values and Keys:
Both maps allow null values and, typically, one null key, which can be very useful in certain applications where null represents a valid state of an element.
-
Non-Synchronized:
Neither HashMap nor LinkedHashMap is synchronized, meaning they are not thread-safe by default. External synchronization is needed if concurrent modifications are expected in a multi-threaded environment.
- Performance:
Both provide fast performance for basic operations such as insertions, deletions, and retrieving values when compared to other map implementations like TreeMap.
-
Custom Load Factors:
Both HashMap and LinkedHashMap can be initialized with a custom load factor, which allows the control of space-time trade-offs related to the internal data structure.
-
Capacity Initialization:
They both allow the initial capacity to be specified during instantiation, which can help in optimizing performance by reducing the need for rehashing as the map grows.