Java’s Collections Framework offers a rich set of data structures designed to store, retrieve, and manipulate data efficiently. Two standout implementations of the Set interface are HashSet and TreeSet. While both are designed to store unique elements, their underlying mechanisms and performance characteristics are quite distinct. In this post, we will learn the differences between HashSet and TreeSet in Java with examples.

Criteria HashSet TreeSet
Underlying Data Structure Hash table Red-Black tree (a type of balanced binary search tree)
Ordering of Elements No guaranteed order Elements are sorted according to their natural ordering or by a comparator provided at set creation time
Null Elements Allows one null element Doesn’t allow any null element (if natural ordering is used or any custom comparator does not permit nulls)
Performance Generally faster for add, remove, and contains operations Logarithmic time cost for add, remove, and contains operations
Duplicates Does not allow duplicates Does not allow duplicates
Thread Safety Not synchronized Not synchronized
Use-case When ordering is not needed, and faster operations are required When sorting or natural order is important

Example: Difference Between HashSet and TreeSet in Java

import java.util.HashSet;
import java.util.Set;
import java.util.TreeSet;

public class HashSetVsTreeSetDemo {

    public static void main(String[] args) {

        // Create a HashSet and add some elements
        Set<String> hashSet = new HashSet<>();
        hashSet.add("cherry");
        hashSet.add("banana");
        hashSet.add("apple");
        hashSet.add("date");

        System.out.println("HashSet:");
        hashSet.forEach(System.out::println);

        // Create a TreeSet and add some elements
        Set<String> treeSet = new TreeSet<>();
        treeSet.add("elephant");
        treeSet.add("grape");
        treeSet.add("fox");
        treeSet.add("honeydew");

        System.out.println("\nTreeSet:");
        treeSet.forEach(System.out::println);
    }
}

Output:

HashSet:
cherry
banana
apple
date

TreeSet:
elephant
fox
grape
honeydew

Explanation:

1. HashSet: A HashSet is an implementation of the Set interface, backed by a hash table (actually a HashMap instance). It does not guarantee the order of elements. This means that the order in which the elements are added is not necessarily the order in which they will be iterated. It offers constant-time performance for the basic operations (add, remove, contains).

2. TreeSet: A TreeSet is a NavigableSet implementation based on a TreeMap. It guarantees the elements to be in ascending order, according to their natural order, or by a comparator provided at the set's creation time. It offers log(n) time complexity for most operations.

3. In the given example, the hashSet does not maintain any order, while the treeSet automatically arranges the strings in their natural order (alphabetically). This is evident in the output where the TreeSet elements are printed in a sorted manner, while the HashSet elements are in a seemingly random order.