HashSet in Java is a collection used to store unique elements. It is part of the Java Collections Framework and is backed by a hash table implementation.
Unlike an ArrayList, a HashSet does not allow duplicate elements. It is particularly useful when the main requirement is to determine whether a value exists, remove duplicates, or maintain a collection of unique values without requiring sorted order.
What Is HashSet in Java?
HashSet<E> implements the
Set interface. A Set represents a collection in which
duplicate elements are not allowed.
For example, if the same language is added multiple times, HashSet keeps only one occurrence.
import java.util.HashSet;
import java.util.Set;
Set<String> languages = new HashSet<>();
languages.add("Java");
languages.add("Python");
languages.add("Java");
System.out.println(languages);
The second "Java" does not create another element because
HashSet only stores unique values.
Creating a HashSet
A HashSet is commonly declared using the Set interface
and initialized with the HashSet implementation.
import java.util.HashSet;
import java.util.Set;
Set<Integer> numbers = new HashSet<>();
numbers.add(10);
numbers.add(20);
numbers.add(30);
Using the Set interface makes it possible to change the
implementation later if the application's ordering or performance requirements change.
Adding Elements to HashSet
Use the add() method to insert an element.
The method returns true when the set changes and
false when the element was already present.
Set<String> skills = new HashSet<>();
boolean first = skills.add("Java");
boolean second = skills.add("Python");
boolean duplicate = skills.add("Java");
System.out.println(first);
System.out.println(second);
System.out.println(duplicate);
System.out.println(skills);
The third call returns false because
"Java" is already contained in the set.
Checking Whether an Element Exists
Use contains() to check whether an element is present.
This is one of the main reasons HashSet is useful compared with a list when frequent
membership checks are required.
Set<String> technologies = new HashSet<>();
technologies.add("Java");
technologies.add("Python");
technologies.add("C#");
System.out.println(technologies.contains("Java"));
System.out.println(technologies.contains("Go"));
Removing Elements from HashSet
The remove() method removes a specified element.
It returns true if the set contained the element.
Set<String> languages = new HashSet<>();
languages.add("Java");
languages.add("Python");
languages.add("C#");
languages.remove("Python");
System.out.println(languages);
Unlike an ArrayList, HashSet does not use indexes, so elements are removed by their values rather than by a numeric position.
Iterating Through a HashSet
HashSet can be traversed using an enhanced for loop.
Set<String> languages = new HashSet<>();
languages.add("Java");
languages.add("Python");
languages.add("C#");
for (String language : languages) {
System.out.println(language);
}
HashSet does not guarantee a predictable iteration order. The order in which elements are printed should not be treated as insertion order or sorted order.
HashSet and Duplicate Values
The defining property of HashSet is that duplicate elements are ignored. This makes it useful for quickly removing duplicate values from a collection.
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
List<Integer> numbers = new ArrayList<>();
numbers.add(10);
numbers.add(20);
numbers.add(10);
numbers.add(30);
numbers.add(20);
Set<Integer> uniqueNumbers = new HashSet<>(numbers);
System.out.println(uniqueNumbers);
The resulting set contains each distinct value only once.
HashSet with Null Values
HashSet permits a single null element.
Adding null again does not create another null entry.
Set<String> values = new HashSet<>();
values.add("Java");
values.add(null);
values.add(null);
System.out.println(values);
System.out.println(values.contains(null));
HashSet Size and Empty Check
Use size() to find the number of unique elements and
isEmpty() to determine whether the set contains no elements.
Set<Integer> numbers = new HashSet<>();
numbers.add(10);
numbers.add(20);
numbers.add(10);
System.out.println(numbers.size());
System.out.println(numbers.isEmpty());
The size is 2 because the value
10 occurs only once in the set.
Clearing a HashSet
The clear() method removes every element from the set.
Set<String> languages = new HashSet<>();
languages.add("Java");
languages.add("Python");
languages.clear();
System.out.println(languages);
System.out.println(languages.isEmpty());
Set Operations in Java
HashSet can perform common mathematical set operations through methods provided by
the Set interface.
Union
addAll() can be used to combine the unique elements
from two sets.
Set<Integer> first = new HashSet<>();
first.add(1);
first.add(2);
first.add(3);
Set<Integer> second = new HashSet<>();
second.add(3);
second.add(4);
second.add(5);
Set<Integer> union = new HashSet<>(first);
union.addAll(second);
System.out.println(union);
Intersection
retainAll() keeps only elements that are present
in both sets.
Set<Integer> common = new HashSet<>(first);
common.retainAll(second);
System.out.println(common);
Difference
removeAll() removes elements that are also present
in another collection.
Set<Integer> difference = new HashSet<>(first);
difference.removeAll(second);
System.out.println(difference);
HashSet vs ArrayList
HashSet and ArrayList are both commonly used collections, but they are designed for different access patterns.
| Feature | HashSet | ArrayList |
|---|---|---|
| Duplicates | Not allowed | Allowed |
| Index access | Not supported | Supported |
| contains() | O(1) average | O(n) |
| Ordering | No guaranteed order | Insertion order |
| Primary use | Uniqueness and membership | Ordered indexed data |
HashSet vs HashMap
HashSet and HashMap both use hashing internally, but their purposes are different.
| Feature | HashSet | HashMap |
|---|---|---|
| Stores | Values | Key-value pairs |
| Duplicate values | Not allowed | Allowed |
| Key | Not applicable | Unique |
| Primary use | Unique values | Key-based lookup |
HashSet Time Complexity
HashSet is designed to provide efficient average-case operations through hashing.
| Operation | Average Complexity |
|---|---|
| add() | O(1) |
| contains() | O(1) |
| remove() | O(1) |
| size() | O(1) |
| Iteration | O(n) |
These are typical average-case complexities. Actual behavior can be affected by hashing, collisions, resizing, and the implementation of the elements stored in the set.
HashSet and hashCode()
HashSet relies on hashCode() and
equals() to determine whether elements are equivalent.
This becomes especially important when custom objects are stored in a HashSet.
If two objects are considered equal according to equals(),
they must return the same hash code. Correctly implementing both methods is therefore
important when custom objects represent set elements.
HashSet with Custom Objects
HashSet can store custom objects, but duplicate detection depends on the object's equality and hash-code contract.
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
class User {
int id;
String name;
User(int id, String name) {
this.id = id;
this.name = name;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof User)) {
return false;
}
User other = (User) obj;
return id == other.id;
}
@Override
public int hashCode() {
return Objects.hash(id);
}
}
public class Main {
public static void main(String[] args) {
Set<User> users = new HashSet<>();
users.add(new User(101, "Alice"));
users.add(new User(101, "Alice"));
System.out.println(users.size());
}
}
Because the two User objects have the same ID and the equality contract treats the ID as the identity of the user, the HashSet considers them equal.
When Should You Use HashSet?
HashSet is useful when the primary requirement is maintaining a collection of unique values and performing membership checks efficiently.
- You need to prevent duplicate values.
- You frequently need to check whether a value exists.
- Ordering is not required.
- You need to remove duplicates from another collection.
- You need to perform operations such as union, intersection, or difference.
- You are solving coding problems involving unique values or membership checks.
Practical Example: Finding Duplicate Values
A HashSet can be used to detect duplicates while traversing an array. If adding an element returns false, that value has already been encountered.
import java.util.HashSet;
import java.util.Set;
public class Main {
public static void main(String[] args) {
int[] numbers = {10, 20, 30, 20, 40, 10};
Set<Integer> seen = new HashSet<>();
for (int number : numbers) {
if (!seen.add(number)) {
System.out.println("Duplicate: " + number);
}
}
}
}
This approach can detect duplicates in average O(n) time because each HashSet insertion is typically O(1).
HashSet vs TreeSet
If unique elements must also remain sorted, TreeSet
may be more appropriate than HashSet.
| Feature | HashSet | TreeSet |
|---|---|---|
| Duplicates | Not allowed | Not allowed |
| Ordering | No guaranteed order | Sorted order |
| contains() | O(1) average | O(log n) |
| Primary purpose | Fast unique-value operations | Sorted unique values |
Common HashSet Mistakes
- Expecting HashSet to preserve insertion order.
- Trying to access HashSet elements using indexes.
- Using HashSet when duplicate values are intentionally required.
- Using HashSet when sorted ordering is a requirement.
- Assuming
contains()is guaranteed O(1) in every possible condition. - Failing to implement
equals()andhashCode()correctly for custom objects. - Modifying objects in ways that affect their equality or hash code while they are stored in the set.
- Using a HashSet when a HashMap is needed to associate keys with values.
Key Takeaways
HashSetstores unique elements.- Duplicate values are automatically ignored.
add()returns false when the element already exists.contains()is typically O(1) on average.- HashSet does not provide index-based access.
- HashSet does not guarantee a predictable iteration order.
- A single
nullelement is permitted. - Custom objects should correctly implement
equals()andhashCode(). - Use TreeSet instead when unique elements also need to remain sorted.