Java HashSet and TreeSet

A Java Set is a collection that stores each value only once. HashSet is usually used for fast uniqueness checks, while TreeSet stores unique values in sorted order.

Both classes are part of java.util and both use generics, such as HashSet<String>, to say what kind of objects the set stores.

Create A HashSet

Use a HashSet when you care whether a value is present, but you do not need the values to stay in insertion order or sorted order. A HashSet does not guarantee the order used when looping or printing.

import java.util.HashSet;

public class Main {
    public static void main(String[] args) {
        HashSet<String> languages = new HashSet<>();

        System.out.println(languages.add("Java"));
        System.out.println(languages.add("Java"));
        languages.add("Python");
        languages.add("C++");

        System.out.println("Size: " + languages.size());
        System.out.println(languages.contains("Python"));
        System.out.println(languages.remove("Ruby"));
    }
}

Output:

true
false
Size: 3
true
false

The first add("Java") returns true because the value was added. The second one returns false because Java was already in the set. After adding three unique values, size() returns 3.

Create A TreeSet

Use a TreeSet when you want unique values and sorted order. Strings are sorted alphabetically, and numbers are sorted from smallest to largest.

import java.util.TreeSet;

public class Main {
    public static void main(String[] args) {
        TreeSet<String> names = new TreeSet<>();

        names.add("Linus");
        names.add("Ada");
        names.add("Grace");
        names.add("Ada");

        System.out.println(names);
        System.out.println("First: " + names.first());
        System.out.println("Last: " + names.last());
        System.out.println("After Ada: " + names.higher("Ada"));
    }
}

Output:

[Ada, Grace, Linus]
First: Ada
Last: Linus
After Ada: Grace

The duplicate Ada is ignored, and the remaining names are stored in sorted order. The first(), last(), and higher() methods are available because TreeSet is a sorted set.

Loop Through A Set

A for-each loop works with sets. With HashSet, do not write code that depends on the loop order. With TreeSet, the loop follows sorted order.

import java.util.TreeSet;

public class Main {
    public static void main(String[] args) {
        TreeSet<Integer> scores = new TreeSet<>();
        scores.add(82);
        scores.add(95);
        scores.add(70);
        scores.add(95);

        for (int score : scores) {
            System.out.println(score);
        }
    }
}

Output:

70
82
95

The duplicate score 95 appears only once. Because this example uses a TreeSet, the loop prints the numbers in sorted order.

HashSet Versus TreeSet

Feature HashSet TreeSet
Duplicates Not allowed Not allowed
Order No guaranteed order Sorted order
Common use Fast membership checks Unique values that must be sorted
Extra methods Basic set methods first(), last(), higher(), and more

Common Set Methods

  • add(value) adds a value if it is not already present.
  • contains(value) checks whether a value is in the set.
  • remove(value) removes a value if it exists.
  • size() returns the number of unique values.
  • clear() removes all values.
  • isEmpty() checks whether the set has no values.

Common Mistakes

  • Expecting a HashSet to print values in the order they were added.
  • Trying to access set values by index. A set has no get(0) method.
  • Forgetting that duplicate values are ignored instead of stored twice.
  • Using TreeSet with values that cannot be compared or sorted.

Takeaway: use HashSet for unique values with fast lookup, and use TreeSet when the unique values should also stay sorted.