Hashtable in Java
The Hashtable class in Java is one of the oldest members of the Java Collection Framework. A hash table is an unordered collection of key-value pairs, with a unique key for each value.
In a hash table, data is stored in an array of list format, with a distinct index value for each data value. The hash table efficiently combines retrieval, edit, and delete operations.
This article explains how to build a hashtable, how to fill it with data, and finally, how to use enumeration to show the key-value pairs in the hashtable. At the end of this article, there are Hashtable code examples, desired outputs, and detailed information regarding Hashtable class methods.
Introduction to Java Hashtable Class
The Hashtable class in Java is a concrete implementation of a Dictionary and was originally part of the java.util package. It creates a hash table by mapping keys to values.
In a hashtable, any non-null object can be used as a key or as a value. The objects used as keys must implement the hashCode and equals methods in order to effectively store and retrieve items from a hashtable.
Hashtable is not just a data structure but also a Java Collection API class. Although both array and hashtable data structures are intended for fast search, i.e., constant-time search operation, also known as O(1) search, the fundamental difference between them is that the array requires an index, whereas the hash table requires a key, which could be another object.
This code example generates a hashtable of numbers. It employs the bird numbers as keys:
Output:
As depicted above, a hashtable does not guarantee the order of records inserted in it.
Java Hashtable was added in the JDK 1.0 version, which is part of the java.util.Hashtable package. Prior to the JDK 1.2 version, keys and values were mapped using hashtables. Later, the Java 1.2 version changed the Hashtable such that it now implements the Map interface. Thus, Hashtable has been included in the Java Collections framework. However, since it does not exactly adhere to the Java Collections Framework, it is now considered a "legacy class."
Declaration
Hashtable in Java is a generic class created by JDK 1.5, which can be declared as follows:
Parameters
Two parameters are accepted by hashtable:
- K – the type of keys maintained by this map
- V – the type of mapped values
Internal Working of Hashtable
Before getting into how hashtables operate in Java, let's have a look at how they're implemented.
The hashtable class extends the Dictionary class and implements Map, Cloneable, and Serializable interfaces. The following diagram clearly depicts the Hashtable hierarchy in Java.
A Hashtable is an array of lists. Each list is referred to as a bucket that contains the key/value pairs in it. It uses the hashCode() method to identify which bucket should be assigned to the key/value combination. Hashcode, in general, uses a non-negative integer that is equal for equal Objects but may or may not be equal for unequal Objects. The hashtable uses the equals() function to detect if two items are equal or not.
The hash function assists in locating a specific key in the bucket list. In theory, a hash function creates an address in a table when given a key. For an object, a hash function always returns a number.
Note: It should be noted that the Java Hashtable class includes unique elements and does not support null keys or values. You cannot even attempt to acquire a null key since it would throw a NullPointerException.
Two identical items will always have the same number. However, two unequal objects might not always have distinct numbers. When we add entries into a hashtable, different objects (through the equals() function) may have the same hashcode. This is referred to as a collision.
The pairings that map to a single bucket (array index) are saved in a list, and the list reference is saved in the array index.
Hashtables are simple to understand when visualized. Hash tables are often created as arrays of linked lists. If we consider a table that stores city names, after a few insertions, it might be laid out in memory as below, where ()-enclosed integers represent hash values of the text entered as the city’s name.
- Each entry in the array (at indices [0], [1], and so on) is called a bucket. It begins with a potentially empty linked list containing key-value pairs, which, in this case, are key-mapped to city names.
- Each value (e.g. "Ontario" with hash 12 ) is linked from a bucket, which is identified by the formula: Hash_number % Number of buckets = Index of Bucket 12 % 10 == [2] Here, % is the modulo operator, which gives the remainder when the hash number is divided by the number of buckets. So, the city name with hash number 12 will be placed in a bucket with the index number 2.
- Multiple data values may collide at and be linked from the same bucket, often due to the fact that their hash values collide after calculating the modulo operation (e.g. 12 % 10 == [2], and 42 % 10 == [2]), Most hash tables manage collisions by comparing the whole value (here text) of a value being searched or added to each value existing in the linked list at the hashed-to bucket. This results in somewhat decreased speed but no functional confusion.
Hashtable is synchronized and offers thread safety comparable to concurrentHashMap. However, from the performance perspective, Hashtable writes operations employ hashtable wide lock, which locks the whole hashtable object.
Look at the below illustration for a better understanding.
To get the lock on the whole hashtable object, thread T1 runs the get() and put() operations on the hashtable. As a result, if Thread T2 performs get() or put(), it must wait until Thread T1 completes the operation and releases the lock on the object.
Features of Hashtable in Java
In Java, a hashtable is a component of the collections framework in which it implements a Map interface. For backward compatibility, it inherits from the obsolete and utterly useless Dictionary class.
After learning what a hashtable in Java is and how it operates, let's examine some of its key features:
-
Key Based Hashtables need a key to search the value, which might be another object, in contrast to arrays, which require an index.
-
Dynamic Capacity By employing chaining and linked lists, the hashtable may store more items than the internal array can hold.
-
Performance Hashtable performance may be O(n) in the worst scenario when you need to go through a linked list to identify the proper value object due to a collision, despite the fact that hashtables are designed for fast search, that is, constant-time search operations, commonly known as O(1) search.
Note: This has been somewhat improved now when JDK utilizes binary tree rather than linked lists from Java 8, and worst-case performance is now pegged to O(logN).
-
Usage Hashtables stores mapping or pairings of key-value objects. As a result, it may be used to hold information on clients, library books, or other records.
-
Sorting Although a Hashtable cannot be sorted, sorted data can be extracted by sorting the list of keys from the Hash table and retrieving values in that order by using a TreeMap or LinkedHashMap.
-
Collision Different data items may collide at and be associated with the same bucket, most often because their hash values conflict. Collisions are possible in hashtables. This can be handled by using various collision avoidance algorithms, like open addressing or chaining.
-
Synchronization Since the hashtable class is synchronized, it is thread-safe. The Hashtable class instance cannot be accessed simultaneously by more than one thread. As a result, its operations are slower than those of HashMaps in Java.
Note: If a thread-safe implementation is not required, it is advisable to use HashMap instead of Hashtable.
Note: If a thread-safe, highly concurrent implementation is needed, ConcurrentHashMap instead of Hashtable should be used.
Constructors of Java Hashtable Class
Both parameterized and non-parameterized constructors may be used to generate a Hashtable in a variety of ways:
Constructor | Description |
---|---|
Hashtable() | It is the default constructor of a hash table that constructs a new and empty hashtable. It has default initial capacity (11) and load factor (0.75). |
Hashtable(int capacity) | It constructs a new, empty hashtable with the given initial capacity and default load factor (0.75). |
Hashtable(int capacity, float loadFactor) | It constructs a new, empty hashtable with the provided initial capacity and the specified load factor. |
Hashtable(Map<? extends K,? extends V> t) | It constructs a new hashtable with exactly the same mappings as the given Map. |
Methods of Java Hashtable Class
The most commonly used methods in HashTable are shown below.
Method | Description |
---|---|
void clear() | Removes all the mappings from a Hashtable and makes it empty. |
Object clone() | Creates a shallow copy of the hashtable. Only the structure of the hashtable itself is copied, but the keys and values are not cloned. |
boolean containsValue(Object value) | Checks if the specified object is a value in the hashtable. Returns true if some value equal to the specified value exists within the hash table. Returns false if the value isn’t found. |
boolean containsKey(Object key) | Checks if the specified object is a key in this hashtable. |
boolean contains(Object value) | Checks if some key maps into the specified value in this hashtable. |
boolean isEmpty() | Tests if the hashtable maps no keys to values. |
Enumeration keys() | Returns an enumeration of the keys contained in the hash table. |
Object put(Object key, Object value) | Maps the specified key to the specified value in this hashtable. |
void rehash() | Increases the size of the hash table and rehashes all of its keys. |
Object remove(Object key) | Removes the key (and its corresponding value) from this hashtable. |
int size() | Returns the number of key-value mappings present in Hashtable. |
String toString() | Returns the objects of Hashtable in the form of a set of key-value mappings separated by ", ". The toString() method is used to convert all the elements of Hashtable into String. |
Enumeration elements() | Returns an enumeration of the values contained in the hash table. |
Object get(Object key) | Returns the value to which the specified key is mapped or null if the hashtable contains no mapping for the key. |
hashcode() | Returns the hash code value for the Map as per the definition in the Map interface. |
putAll(Map<? extends K,? extends V> t) | Copies all of the mappings from a given map to the hashtable. |
getOrDefault(Object key, V defaultValue) | Returns the value to which the given key is mapped, or defaultValue if the hashtable contains no mapping for the key. |
putIfAbsent(K key, V value) | If the specified key is not already mapped with a value, maps it with the given value and returns null, else returns the current mapped value. |
keySet() | Returns a view of the keys contained in the hashtable as a set. |
entrySet() | Returns a view of the mappings contained in the hashtable as a set. |
Code Examples Using Hashtable in Java
Let's look at a few example methods that conduct operations using hashtable in Java.
- Hashtable()
Output:
- remove()
This example shows how to remove elements from a hashtable by using the remove() function.
This function takes the key of the value to be removed as the parameter.
Output:
- getOrDefault()
This example shows how to use the getOrDefault() function, which returns the value to which a specified key is mapped or a defaultValue if the hashtable does not contain a mapping for that key.
It takes two parameters: a key and a default value to be printed as a message if the key is not present in the hashtable.
Output:
- putIfAbsent()
This example shows how to use the putIfAbsent() function which allows mapping a value to a given key if a given key is not associated with the value or mapped to null.
It takes two parameters, a key and a value, to be mapped with the key. If the key-value pair is unique, then it gets inserted in the hashtable; otherwise, there are no changes in the hashtable.
Output:
- Traversal of a Hashtable
We may traverse through the hashtable in a number of different methods, which are as follows:
1. Using Enumeration Interface
The java.util.Enumeration interface is used to get the data from collections framework variables like a stack or a hashtable only in the forward and not in the backward direction. It is one of the predefined interfaces.
Note: Enumeration is regarded as obsolete for new code, and this interface has been replaced with an iterator.
Example:
Output:
2. Using keySet() method of Map and Enhance for loop
The java.util.HashMap.keySet() function in Java generates a set from the key elements in the hash map.
It simply returns a view of the keys as a set, or we can construct a new set and store its key elements.
Example:
Output:
3. Using keySet() method of Map and Iterator Interface
This example uses the same approach as the previous method, however, iteration is performed here by using an Iterable interface.
Example:
Output:
4. Using entrySet() method of Map and Enhanced For Loop
The java.util.HashMap.entrySet() method in Java is used to build a set from the same elements found in the hash map.
It returns a view of the hash map as a set, or we can construct a new set and store the map elements in it.
Example:
Output:
5. Using entrySet() method of Map and Iterator interface
This example uses the same approach as the above method, however, iteration is performed here by using an Iterable interface.
Example:
Output:
6. Using Iterable.forEach() method from version Java 8
With the release of Java 8, several old APIs have been updated, and new features are added.
One of them is forEach() method in java.lang.Iterable Interface which performs a given action for every element of the Iterable until each elements have been processed or it throws an exception.
It performs the actions in the order of iteration unless specified otherwise.
Example:
Output:
- Hashtable(Map<? extends K,? extends V> m)
This example shows how to construct a new hashtable with the same mappings as a given Map.
Output:
- Hashtable(int size, float fillRatio)
This example shows a Hashtable constructor which takes a whole number depicting the initial capacity of the Hashtable and a positive loadFactor as arguments.
Output:
- Hashtable(int initialCapacity)
This example shows a Hashtable constructor, which takes a whole number as an argument for depicting the initial capacity of the Hashtable.
Output:
Conclusion
- This article covered the characteristics of the Java Hashtable class, its constructors, methods, and actual use cases.
- It are used to store and retrieve data (or records) quickly.
- Hashtables store the records in buckets using hash keys.
- Java Hashtable implements the Serializable and Cloneable interfaces but not the random access interface.
- Java Hashtable does not support null for both keys and values.
- In a hashtable, every method is synchronized. Hence, the Hashtable object is thread-safe.
- Although Hashtable is thread-safe, it performs poorly with multiple threads.