HashSet in Java

HashSet in Java

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

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
quiz-icon

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:

Java

Output:

Declaring a HashSet

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.

Performing Various Operations on HashSet

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:

Java

Output:

Adding Elements in HashSet

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:

Java

Output:

Removing Elements in HashSet

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:

Java

Output:

terating through the HashSe

Explanation:

In the above Java code, the HashSet is traversed using the for-each loop and then by using the iterator.

Performance of HashSet

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
quiz-icon

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.

About the Author

Technical Research Analyst - Full Stack Development

Kislay is a Technical Research Analyst and Full Stack Developer with expertise in crafting Mobile applications from inception to deployment. Proficient in Android development, IOS development, HTML, CSS, JavaScript, React, Angular, MySQL, and MongoDB, he’s committed to enhancing user experiences through intuitive websites and advanced mobile applications.

Full Stack Developer Course Banner