๐ What Is a HashSet?
A HashSet is a collection in Java that stores unique elements โ no duplicates allowed.
Itโs part of the java.util package and is backed by a HashMap internally.
Think of it like a bag of unique cards ๐ด โ if you try to add the same card again, it just ignores it.
โ๏ธ Quick Example
import java.util.HashSet;
public class HashSetExample {
public static void main(String[] args) {
HashSet<String> countries = new HashSet<>();
countries.add("Japan");
countries.add("Canada");
countries.add("Japan"); // duplicate ignored
System.out.println(countries); // [Japan, Canada]
System.out.println("Contains Canada? " + countries.contains("Canada")); // true
}
}
โ
Output:
[Japan, Canada]
Contains Canada? true
๐ง Notice how โJapanโ appears only once โ HashSet automatically handles duplicates.
โ๏ธ How It Works Internally
Under the hood, a HashSet uses a HashMap where:
Elements are stored as keys.
A dummy value (usually a static constant) acts as the value.
When you call add(element):
The elementโs hashCode() is computed.
Itโs placed into a bucket based on that hash.
If another element has the same hash (collision), itโs stored in a linked list or tree within that bucket.
The equals() method ensures duplicates are not added.
โ๏ธ Common Methods
| Method | Description |
|---|---|
add(E e) |
Adds element if not already present |
remove(Object o) |
Removes element |
contains(Object o) |
Checks if element exists |
isEmpty() |
Returns true if empty |
size() |
Returns number of elements |
clear() |
Removes all elements |
๐งฎ Time Complexity
| Operation | Average | Worst Case |
|---|---|---|
| add() | O(1) | O(n) |
| remove() | O(1) | O(n) |
| contains() | O(1) | O(n) |
| iteration | O(n) | O(n) |
โก HashSet provides constant-time performance for most operations โ thatโs why itโs widely used for lookups and membership checks.
๐ก Key Features
๐ซ No duplicates โ each element is unique.
โก Fast lookup using hashing.
๐ No guaranteed order โ iteration order may differ from insertion order.
๐ฆ Allows one null element.
โ Not thread-safe โ use Collections.synchronizedSet() for concurrency.
๐ Example: Removing Duplicates from a List
import java.util.*;
public class RemoveDuplicates {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 2, 3, 4, 4, 5);
HashSet<Integer> unique = new HashSet<>(numbers);
System.out.println(unique); // [1, 2, 3, 4, 5]
}
}
๐ This is one of the most common and elegant uses of a HashSet.
๐ Example: Checking Membership Efficiently
HashSet<String> users = new HashSet<>();
users.add("mohammed");
users.add("ahmed");
if (users.contains("mohammed")) {
System.out.println("Welcome back!");
}
This operation is instant (O(1)) โ much faster than searching a list.
๐งฉ HashSet vs TreeSet vs LinkedHashSet
| Feature | HashSet | LinkedHashSet | TreeSet |
|---|---|---|---|
| Order | No order | Maintains insertion order | Sorted order |
| Speed | Fastest | Slightly slower | Slower (due to sorting) |
| Backed By | HashMap | LinkedHashMap | TreeMap |
| Allows Null | Yes | Yes | No |
| Use Case | Unordered unique items | Preserve insertion order | Sorted unique items |
๐ Real-World Uses of HashSet
- ๐งพ Removing Duplicates
Cleaning up data โ for example, user emails or IDs that appear multiple times.
- ๐ Checking Membership
Efficient โalready exists?โ checks (e.g., registered usernames, cached results).
- ๐ง Tracking Unique Events
Game achievements, visited URLs, or user actions that should happen only once.
- ๐ Efficient Lookup Tables
Fast lookups for values without caring about order โ like tags, keywords, or filters.
โ๏ธ Example: Unique Visitors in a Web App
import java.util.HashSet;
public class UniqueVisitors {
public static void main(String[] args) {
HashSet<String> visitors = new HashSet<>();
visitors.add("user123");
visitors.add("guest456");
visitors.add("user123"); // duplicate
System.out.println("Unique visitors: " + visitors.size());
}
}
โ Output:
Unique visitors: 2
โ ๏ธ Common Mistakes
โ Expecting insertion order โ HashSet does not maintain it.
โ Forgetting to override hashCode() and equals() in custom objects.
โ Using mutable objects as keys โ changing them breaks hash consistency.
๐งฉ Example: Custom Object in HashSet
import java.util.*;
class Student {
String name;
int id;
Student(String name, int id) {
this.name = name;
this.id = id;
}
@Override
public int hashCode() {
return Objects.hash(id);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Student)) return false;
Student s = (Student) o;
return id == s.id;
}
}
public class CustomHashSet {
public static void main(String[] args) {
HashSet<Student> set = new HashSet<>();
set.add(new Student("Ali", 1));
set.add(new Student("Ali", 1)); // duplicate ignored
System.out.println("Total students: " + set.size()); // 1
}
}
Without overriding hashCode() and equals(), this would incorrectly count as 2 students.
๐ก Final Thought
The HashSet is your go-to structure when you want uniqueness and speed without worrying about order.
Itโs one of the fastest and most memory-efficient collections in Java โ a real workhorse behind the scenes of many high-performance systems. โก
Top comments (0)