HashSet in Java is a special collection that stores only unique items. It does not keep things in order, but it is very fast when adding, searching, or removing elements. It uses a hashing technique to quickly find items. HashSet is useful when you want to avoid duplicates and don’t care about the order of elements.
In this article, we will learn about the HashSet in detail, with its limitations and features.
Table of Contents:
What is a HashSet in Java?
HashSet is a class in Java that is used to store a group of unique elements. It is a part of the Java Collections Framework and is present in the java.util package.
HashSet is made up of two words, Hash and Set, which means the following:
- Hash: It uses the technique of hashing to store elements, which allows the fast operations of search, insert, and delete operations.
- Set: It is a set in maths that stores unique elements. It does not maintain the order of the elements that are stored in it.
Hierarchy of HashSet
In the above figure, the detailed view of the hierarchy of the HashSet is given. Further, the brief of which can be discussed as below.
java.lang.Object
java.util.AbstractCollection<E>
java.util.AbstractSet<E>
java.util.HashSet<E>
Now, let us see each level in detail.
1. Object
It is the root class of all Java Classes. Every class in Java directly or indirectly inherits from Object.
2. AbstractCollection<E>
It provides the basic implementation for methods in the Collection interface.
3. AbstractSet<E>
It ensures that sets do not allow duplicate elements.
4. HashSet<E>
It extends AbstractSet and provides a full implementation of the Set interface using a hash table.
Master Java Today - Accelerate Your Future
Enroll Now and Transform Your Future
Declaring a HashSet
In Java, you declare a HashSet using the HashSet class from the java.util package. Below is a detailed explanation of it.
Syntax:
HashSet<Type> setName = new HashSet<>();
Let us discuss it now with the help of an example.
Example:
Output:
Explanation:
In the above Java code, the HashSet of type String is used, in which Java is used twice, out of which only one element will be added. Also, a null value is added to it.
Internal Working of HashSet
So, before moving further, let us discuss the working of the hashset. HashSet uses the following process to store its elements.
1. Compute the Hash Code
When an element is added to the HashSet, it first calls the hashCode() method of that object.
2. Apply Hashing
In this step, the bucket index is searched where an element can be stored. Buckets are like slots in an array, where each element is stored.
3. Check for Duplicates using equals()
In this step, if any other element is already present in that bucket, it then uses the equals() method to check if the elements are the same.
If equals() returns true, then the element is considered a duplicate and it is not added to the HashSet.
4. Add to Map
HashSet internally uses a HashMap where the key is the element, and the value is a constant placeholder object, commonly named PRESENT.
Constructors of the HashSet Class
Constructor |
Description |
HashSet() |
Creates empty HashSet with default initial capacity (16) and load factor (0.75) |
HashSet(int initialCapacity) |
Creates empty HashSet with specified initial capacity and default load factor (0.75) |
HashSet(int initialCapacity, float loadFactor) |
Creates empty HashSet with specified initial capacity and load factor |
HashSet(Collection<? extends E> c) |
Creates HashSet containing elements from specified collection (removes duplicates) |
Methods in Java HashSet
Feature |
BufferedReader |
Scanner |
Speed |
Faster (uses buffering) |
Slower (token-based) |
Ease of Use |
Requires manual conversion |
Easy to use |
Reads Data |
Only strings (needs conversion) |
Strings, numbers, booleans |
Best For |
Large files, performance |
General user input |
Exception Handling |
Requires try-catch (IOException) |
Built-in exception handling |
Memory Usage |
Low (uses buffering) |
Higher (parses input) |
Methods |
readLine() |
nextInt(), nextLine(), nextDouble(), etc. |
1. Adding Elements in HashSet
To add elements to a HashSet in Java, you can use the add() method to add an element to it. Further, if you add a duplicate element to it, it will be ignored.
Example:
Output:
Explanation:
In the above Java code, the elements are added to the HashSet. The duplicate elements are ignored, and only the unique elements are added.
Get 100% Hike!
Master Most in Demand Skills Now!
2. Removing Elements in HashSet
You can remove a single element from a HashSet in Java using the remove() method. If you want to remove all the elements, you can use the clear() method.
Example:
Output:
Explanation:
In the above Java code, firstly, the elements are added to the HashSet. Then, element 20 is removed from it by using the .remove method, after which the .clear method is used to remove all the elements from the hash set.
3. Iterating through the HashSet
You can use a for-each loop or an iterator through a HashSet for traversing.
Example:
Output:
Explanation:
In the above Java code, the HashSet is traversed using the for-each loop and then by using the iterator.
HashSet is fast because instead of checking every item one by one in it, it directly goes to the correct element using the hash code of that item, which makes the operation like addition and subtraction very quick.
Main operations in the HashSet and their speed
Feature |
BufferedReader |
Scanner |
Speed |
Faster (uses buffering) |
Slower (token-based) |
Ease of Use |
Requires manual conversion |
Easy to use |
Reads Data |
Only strings (needs conversion) |
Strings, numbers, booleans |
Best For |
Large files, performance |
General user input |
Exception Handling |
Requires try-catch (IOException) |
Built-in exception handling |
Memory Usage |
Low (uses buffering) |
Higher (parses input) |
Methods |
readLine() |
nextInt(), nextLine(), nextDouble(), etc. |
Note: O(1) means the time it takes does not increase even if there are 100 or 1000 items. But sometimes it can become slower, i.e., O(n), when more than one item goes to the same shelf.
Load factor is a decision that determines when to increase the capacity of the HashSet. It is the ratio of the number of elements to the bucket size before resizing it. The default value of the load factor in Java is 75%, i.e., when the number of stored elements in the HashSet becomes 75% of the total size, the HashSet will resize itself, and will double its size as before to reduce crowding.
The higher the load factor, the less memory is used, and it becomes slower. The lower the load factor, the more memory is used, and the faster the operation..
A HashSet starts with a fixed number of buckets. If the size of the HashSet gets full, it creates a bigger capacity and moves all the items to the new buckets. This process is known as resizing, and it takes the time of about O(n) time.
If you know that you have to store many items, you should have set the size of the HashSet more, like
HashSet<String> set = new HashSet<>(1000);
The HashSet can sometimes become slow because of the following reasons.
1. If different elements return the same hash code, they go to the same shelf because of which means searching takes longer.
2. If the HashSet has more elements than expected, then it resizes itself, which is a slow process.
3. The hash code method should be such that it returns a unique value every time, if not everything will go in 1 bucket, which will make the searching slow.
Features of HashSet in Java
HashSet in Java offers several features. Some of them are:
1. Framework: It is part of the Java Collection Framework
2. Implements Set Interface: It implements the Set interface.
3. Backed by HashMap: HashSet internally uses the HashMap, which is used to store the unique values in the HashSet. Due to which it gives a good time performance for various operations like addition, subtraction, etc.
4. No Guaranteed Order: HashSet does not maintain the order of the values that are stored in it. The values are stored on the basis of their hash code values.
5. Allows Null Elements: HashSet only allows a single null value to be stored in it.
6. Non-Synchronized: HashSet is not synchronized, i.e., it is not thread safe by default.
7. Efficient Performance: It provides a constant time performance for most of the operations like Add(), remove(), and contains().
8. Generic Support: Like the other collections, HashSet supports generics, which allows you to restrict the type of elements. This provides type safety.
HashSet vs. ArrayList vs. HashMap vs. TreeSet
Feature |
HashSet |
ArrayList |
HashMap |
TreeSet |
Based on |
HashMap |
Dynamic Array |
Hash Table |
Red-Black Tree |
Duplicates Allowed |
No |
Yes |
Not for keys, only for values |
No |
Order Maintained |
No |
Yes, insertion order |
No |
Yes, sorted order |
Allows Null |
only one |
multiple |
One null key, many null values |
only one, if allowed |
Search Time |
O(1) |
O(n) |
O(1) |
O(log n) |
Thread Safe |
No |
No |
No |
No |
Use Case |
Store unique items |
Store the ordered list with duplicates |
Store key-value pairs |
Store sorted unique items |
Best Practices for Using HashSet
1. You should use a HashSet only when you need to store unique elements.
2. If you store the custom objects in the HashSet, override both equals() and hashCode() to ensure that the HashSet detects the duplicate correctly.
3. If you know the approximate number of elements to be stored in the HashSet, then set its initial capacity, so that resizing does not occur.
4. Use the contains() method to check if the element exists or not in the HashSet.
5. HashSet only allows one null to be stored in it. Hence, storing more than one null can lead to confusion.
Limitations of HashSet and When Not to Use It
1. HashSet does not maintain the order of the elements, hence insertion order is not preserved. Hence, do not use HashSet when you need to preserve the insertion order.
2. When multiple threads access the HashSet without synchronization, it can cause unexpected behaviour.
3. The performance of the HashSet directly depends on the hashCode(), which can lead to Incorrect behavior, e.g., duplicate elements not detected.
4. Do not use the HashSet when you need to store the elements in sorted order.
5. Do not use HashSet when memory usage is important.
Unlock Your Future in Java
Start Your Java Journey for Free Today
Conclusion
HashSet is a way to store unique elements in Java. It is fast, easy to use, and does not allow duplicate values. It does not keep the order of elements and allows only one null value. It works well when you need quick retrieval and no order of the elements. HashSet internally uses the HashMap to store its elements. It should be only used when uniqueness matters most. It is part of the Java Collections Framework and is commonly used in everyday coding.
If you want to learn more about this topic, you can refer to our Java course.
HashSet in Java – FAQs
Q1. What is the difference between HashMap and HashSet?
HashMap stores things in pairs, key and value, while HashSet only stores single unique items.
Q2. What is the difference between a Set and a HashSet?
Set is an interface, while HashSet is its implementation that uses a hash table.
Q3. Is HashSet faster than HashMap?
Yes, HashSet can be a bit faster if you just need to store unique values.
Q4. Can a HashSet have duplicates?
No, HashSet does not allow duplicate elements.
Q5. Is HashSet synchronized?
No, HashSet is not synchronized by default.