Learn the difference between HashSet and TreeSet in Java with clear examples, simple explanations, and best practices for efficient set operations.
🏁 Introduction
Imagine you’re organizing a list of your favorite books — but you don’t want duplicates. Naturally, you’d make a set — a collection that holds only unique items.
In Java, two popular classes help us do this: HashSet and TreeSet. While both store unique elements, they behave very differently under the hood. Knowing when to use which can make your code faster, cleaner, and more efficient.
In this article, we’ll explore the key differences between HashSet and TreeSet, break them down with examples, and highlight best practices every Java developer should know.
💡 Core Concepts
🔹 What is a HashSet?
A HashSet is a part of the Java Collections Framework and is implemented using a HashMap internally.
It stores elements in an unordered way and ensures that no duplicates are allowed.
- Order: Elements are not stored in any particular order.
- Performance: Offers constant time (O(1)) performance for basic operations like add, remove, and contains (on average).
- Null Elements: Allows one null element.
You’d use a HashSet when order doesn’t matter, and you just want fast lookups and insertions — like keeping track of unique usernames or product IDs.
🔹 What is a TreeSet?
A TreeSet is based on a TreeMap and stores elements in a sorted (ascending) order by default.
It maintains elements in their natural order (for example, numbers in increasing order or strings in alphabetical order).
- Order: Elements are always sorted.
- Performance: Operations like add, remove, and contains take O(log n) time because they use a balanced binary search tree (Red-Black Tree).
-
Null Elements: Does not allow null (throws
NullPointerException).
You’d use a TreeSet when you want to maintain sorted data, like displaying names alphabetically or sorting scores dynamically.
🔸 Key Differences at a Glance
| Feature | HashSet | TreeSet |
|---|---|---|
| Underlying Structure | HashMap | TreeMap |
| Order of Elements | Unordered | Sorted (ascending by default) |
| Performance (add/remove/contains) | O(1) average | O(log n) |
| Allows Null | Yes (one null) | No |
| Thread Safety | Not synchronized | Not synchronized |
| When to Use | Fast operations, order doesn’t matter | Sorted order needed |
💻 Code Examples
✅ Example 1: Using HashSet (Unordered Collection)
import java.util.HashSet;
import java.util.Set;
public class HashSetExample {
public static void main(String[] args) {
Set<String> cities = new HashSet<>();
cities.add("Delhi");
cities.add("Mumbai");
cities.add("Chennai");
cities.add("Kolkata");
cities.add("Mumbai"); // duplicate, will be ignored
System.out.println("Cities in HashSet: " + cities);
// Check membership
if (cities.contains("Delhi")) {
System.out.println("Delhi is present in the HashSet");
}
}
}
🧩 Explanation:
HashSet doesn’t guarantee any particular order. Even though we added “Delhi” first, it might not appear first when printed. Duplicates like “Mumbai” are automatically ignored.
This makes HashSet lightning-fast for lookups and ideal when order doesn’t matter.
✅ Example 2: Using TreeSet (Sorted Collection)
import java.util.Set;
import java.util.TreeSet;
public class TreeSetExample {
public static void main(String[] args) {
Set<Integer> scores = new TreeSet<>();
scores.add(50);
scores.add(80);
scores.add(20);
scores.add(40);
System.out.println("Scores in TreeSet (Sorted): " + scores);
// Accessing the smallest and largest elements
System.out.println("Lowest Score: " + ((TreeSet<Integer>) scores).first());
System.out.println("Highest Score: " + ((TreeSet<Integer>) scores).last());
}
}
🧩 Explanation:
Here, TreeSet automatically stores elements in sorted order (ascending) — even though we added them randomly.
If you need to maintain sorting or easily fetch the smallest/largest elements, TreeSet is perfect.
🧠 Best Practices
Choose HashSet for speed.
If order doesn’t matter and you need fast operations, preferHashSet.Use TreeSet when sorting is essential.
If your use case needs natural or custom ordering (viaComparator), go forTreeSet.Avoid using null in TreeSet.
Adding a null value will cause aNullPointerException.Don’t rely on HashSet order.
The order may change depending on hash codes and internal resizing — avoid using it where order matters.Consider LinkedHashSet for predictable iteration order.
If you need insertion order but still want uniqueness, useLinkedHashSet. It’s a good middle ground.
🏁 Conclusion
Both HashSet and TreeSet help you store unique elements, but they serve different purposes:
- Use HashSet for speed and efficiency when order doesn’t matter.
- Use TreeSet for sorted data and navigation.
Understanding these differences will help you write cleaner, more efficient, and bug-free Java code. Knowing when to use each one is a hallmark of a smart Java developer.
Top comments (0)