DEV Community

realNameHidden
realNameHidden

Posted on

🌳 Difference Between HashSet and TreeSet in Java

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");
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

🧩 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());
    }
}
Enter fullscreen mode Exit fullscreen mode

🧩 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

  1. Choose HashSet for speed.
    If order doesn’t matter and you need fast operations, prefer HashSet.

  2. Use TreeSet when sorting is essential.
    If your use case needs natural or custom ordering (via Comparator), go for TreeSet.

  3. Avoid using null in TreeSet.
    Adding a null value will cause a NullPointerException.

  4. Don’t rely on HashSet order.
    The order may change depending on hash codes and internal resizing — avoid using it where order matters.

  5. Consider LinkedHashSet for predictable iteration order.
    If you need insertion order but still want uniqueness, use LinkedHashSet. 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)