00:00

Set Interface in Java – Complete Guide with Examples

The Set interface represents a collection that cannot contain duplicate elements. If you add a value that is already present, the set simply ignores it. Set lives in java.util, extends Collection, and has been part of the Collections Framework since JDK 1.2.

Sets are the natural choice whenever uniqueness matters: unique visitors, unique tags, removing duplicates, or checking quickly whether something has been seen before. This tutorial covers the Set implementations, their ordering, set operations, and the equals()/hashCode() rules that make sets work.

1. What Is a Set?

Think of a guest list at a party. Each name appears once; writing a name a second time does not add a second guest. Java's Set follows the same rule, modelled on the mathematical idea of a set.

  • No duplicates: two elements e1 and e2 with e1.equals(e2) cannot both be in the set.
  • No indexes: there is no get(i); you loop over a set or check membership with contains().
  • Order depends on the class: none, insertion order, or sorted order.
  • Fast lookups: HashSet.contains() runs in constant time on average.
  • At most one null in HashSet and LinkedHashSet; none in TreeSet or Set.of().

2. Hierarchy and Declaration

Set interface hierarchy in Java
java.util.Set
public interface Set<E> extends Collection<E>

The sub-interfaces SortedSet and NavigableSet add sorted-order features and are implemented by TreeSet. Java 21 added SequencedSet, implemented by LinkedHashSet and the sorted sets.

3. Using a Set: The Basics

A set uses the methods of Collection. The interesting one is add(): it returns false when the element is already present.

SetBasics.java
import java.util.HashSet;
import java.util.Set;

public class SetBasics {
    public static void main(String[] args) {
        Set<String> visitors = new HashSet<>();

        System.out.println("add(Asha):  " + visitors.add("Asha"));
        System.out.println("add(Ravi):  " + visitors.add("Ravi"));
        System.out.println("add(Asha):  " + visitors.add("Asha"));   // duplicate ignored

        System.out.println("Visitors:   " + visitors);
        System.out.println("Count:      " + visitors.size());
        System.out.println("Has Ravi?   " + visitors.contains("Ravi"));

        visitors.remove("Ravi");
        System.out.println("After remove: " + visitors);
    }
}
Output
add(Asha):  true
add(Ravi):  true
add(Asha):  false
Visitors:   [Asha, Ravi]
Count:      2
Has Ravi?   true
After remove: [Asha]

4. Set Implementations

The three everyday implementations differ mainly in the order in which they return elements:

SetImplementations.java
import java.util.*;

public class SetImplementations {
    public static void main(String[] args) {
        List<Integer> input = List.of(42, 7, 19, 7, 3, 42, 25);

        Set<Integer> hash = new HashSet<>(input);
        Set<Integer> linked = new LinkedHashSet<>(input);
        Set<Integer> tree = new TreeSet<>(input);

        System.out.println("Input:         " + input);
        System.out.println("HashSet:       " + hash + "   (no guaranteed order)");
        System.out.println("LinkedHashSet: " + linked + "   (insertion order)");
        System.out.println("TreeSet:       " + tree + "   (sorted)");
    }
}
Output
Input:         [42, 7, 19, 7, 3, 42, 25]
HashSet:       [19, 3, 7, 25, 42]   (no guaranteed order)
LinkedHashSet: [42, 7, 19, 3, 25]   (insertion order)
TreeSet:       [3, 7, 19, 25, 42]   (sorted)
ClassInternal structureOrderadd / contains / removenull
HashSetHash table (a HashMap)No guaranteed orderO(1)One allowed
LinkedHashSetHash table + linked listInsertion orderO(1)One allowed
TreeSetRed-black tree (a TreeMap)SortedO(log n)Not allowed
EnumSetBit vectorEnum declaration orderO(1), very fastNot allowed
CopyOnWriteArraySetArray copied on writeInsertion orderO(n)Allowed
ConcurrentSkipListSetSkip listSortedO(log n), thread-safeNot allowed
Note: the HashSet order in the output above is not something you can rely on. It depends on the hash codes and the table size, and can change when elements are added or between Java versions.

5. Set Operations: Union, Intersection, Difference

Sets make the classic set operations easy. Each bulk method changes the set it is called on, so copy the original first.

SetOperations.java
import java.util.Set;
import java.util.TreeSet;

public class SetOperations {
    public static void main(String[] args) {
        Set<String> java = Set.of("Asha", "Ravi", "Meera", "John");
        Set<String> python = Set.of("Ravi", "John", "Kiran");

        Set<String> union = new TreeSet<>(java);
        union.addAll(python);
        System.out.println("Learn Java or Python:   " + union);

        Set<String> both = new TreeSet<>(java);
        both.retainAll(python);
        System.out.println("Learn both:             " + both);

        Set<String> onlyJava = new TreeSet<>(java);
        onlyJava.removeAll(python);
        System.out.println("Learn only Java:        " + onlyJava);

        System.out.println("Is {Ravi, John} a subset of Java? " + java.containsAll(Set.of("Ravi", "John")));
    }
}
Output
Learn Java or Python:   [Asha, John, Kiran, Meera, Ravi]
Learn both:             [John, Ravi]
Learn only Java:        [Asha, Meera]
Is {Ravi, John} a subset of Java? true
OperationCode
Union (A ∪ B)a.addAll(b)
Intersection (A ∩ B)a.retainAll(b)
Difference (A − B)a.removeAll(b)
Subset (B ⊆ A)a.containsAll(b)

6. equals() and hashCode(): How a Set Finds Duplicates

A HashSet uses an element's hashCode() to pick a bucket, then equals() to compare with the elements already in that bucket. If your class does not override both methods, two objects with the same data are treated as different, and the set ends up with "duplicates".

CustomObjectsInSet.java
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;

public class CustomObjectsInSet {

    // No equals()/hashCode(): every object is "different"
    static class PointNoEquals {
        final int x, y;
        PointNoEquals(int x, int y) { this.x = x; this.y = y; }
    }

    // equals() and hashCode() based on the fields
    static class Point {
        final int x, y;
        Point(int x, int y) { this.x = x; this.y = y; }
        @Override public boolean equals(Object o) {
            return o instanceof Point p && p.x == x && p.y == y;
        }
        @Override public int hashCode() { return Objects.hash(x, y); }
    }

    // A record gets equals() and hashCode() automatically
    record Pixel(int x, int y) { }

    public static void main(String[] args) {
        Set<PointNoEquals> a = new HashSet<>();
        a.add(new PointNoEquals(1, 2));
        a.add(new PointNoEquals(1, 2));
        System.out.println("Without equals/hashCode: size = " + a.size());

        Set<Point> b = new HashSet<>();
        b.add(new Point(1, 2));
        b.add(new Point(1, 2));
        System.out.println("With equals/hashCode:    size = " + b.size());

        Set<Pixel> c = new HashSet<>();
        c.add(new Pixel(1, 2));
        c.add(new Pixel(1, 2));
        System.out.println("With a record:           size = " + c.size());
    }
}
Output
Without equals/hashCode: size = 2
With equals/hashCode:    size = 1
With a record:           size = 1
  • If two objects are equal, they must have the same hash code.
  • Use the same fields in both methods, and prefer immutable fields.
  • Never change an element's fields while it is in a set. Its hash code would change, and the set would no longer find it.
  • TreeSet uses compareTo() or a Comparator instead; elements that compare as 0 are treated as duplicates.

7. Immutable Sets with Set.of()

Java 9 added Set.of() for small, fixed sets, and Java 10 added Set.copyOf(). Both create unmodifiable sets that reject null.

ImmutableSets.java
import java.util.*;

public class ImmutableSets {
    public static void main(String[] args) {
        Set<String> roles = Set.of("ADMIN", "USER");
        try {
            roles.add("GUEST");
        } catch (UnsupportedOperationException e) {
            System.out.println("Set.of() is unmodifiable");
        }

        try {
            Set.of("A", "A");
        } catch (IllegalArgumentException e) {
            System.out.println("Set.of() rejects duplicates: " + e.getMessage());
        }

        List<String> withDupes = List.of("x", "y", "x");
        Set<String> copy = Set.copyOf(withDupes);   // duplicates are dropped here
        System.out.println("Set.copyOf() size: " + copy.size());
    }
}
Output
Set.of() is unmodifiable
Set.of() rejects duplicates: duplicate element: A
Set.copyOf() size: 2

Notice the difference: Set.of() treats duplicate arguments as a programming mistake and throws, while Set.copyOf() quietly drops duplicates from the source collection. The iteration order of these sets is unspecified and may differ between runs.

8. Removing and Finding Duplicates

Two of the most common uses of a set: turning a list into unique values, and finding which values repeat.

RemoveDuplicatesWithSet.java
import java.util.*;

public class RemoveDuplicatesWithSet {
    public static void main(String[] args) {
        List<String> emails = List.of("a@x.com", "b@x.com", "a@x.com", "c@x.com", "b@x.com");

        Set<String> unique = new LinkedHashSet<>(emails);   // keeps first-seen order
        System.out.println("Unique emails: " + unique);

        // Find the duplicates: add() returns false the second time
        Set<String> seen = new HashSet<>();
        Set<String> duplicates = new TreeSet<>();
        for (String e : emails) {
            if (!seen.add(e)) duplicates.add(e);
        }
        System.out.println("Duplicates:    " + duplicates);
    }
}
Output
Unique emails: [a@x.com, b@x.com, c@x.com]
Duplicates:    [a@x.com, b@x.com]

9. Methods of the Set Interface

Set adds no new abstract methods to Collection; it tightens their meaning so that duplicates are never stored. It also adds static factory methods.

MethodDescription
add(e)Adds the element if it is not already present; returns false otherwise.
addAll(c)Adds every element of c that is not present (union).
remove(o)Removes the element if present.
removeAll(c), retainAll(c)Difference and intersection.
contains(o), containsAll(c)Membership and subset checks.
size(), isEmpty(), clear()Count, check and empty.
iterator(), forEach(), stream()Visit the elements.
equals(o), hashCode()Two sets are equal if they contain the same elements, in any order.
Set.of(...), Set.copyOf(c)Create unmodifiable sets (Java 9 and 10).

10. Which Set Should You Use?

  • HashSet: you only need uniqueness and fast lookups. This is the default.
  • LinkedHashSet: you also want elements back in the order they were added.
  • TreeSet: you want elements sorted, or need "smallest", "largest" or "nearest" queries.
  • EnumSet: the elements are enum constants.
  • ConcurrentHashMap.newKeySet() or ConcurrentSkipListSet: several threads share the set.
  • Set.of(): a small fixed set of constants.

11. Set vs List

FeatureSetList
DuplicatesNot allowedAllowed
Access by indexNoYes
OrderDepends on the classInsertion order
contains()O(1) for HashSetO(n)
EqualitySame elements, any orderSame elements, same order

12. Common Mistakes

  • Forgetting equals() and hashCode() in your own classes, so "duplicates" appear.
  • Changing an element after adding it, so contains() and remove() no longer find it.
  • Relying on HashSet order; use LinkedHashSet or TreeSet when order matters.
  • Adding null to a TreeSet, which throws NullPointerException.
  • Calling add() on Set.of(), which throws UnsupportedOperationException.
  • Removing inside a for-each loop; use removeIf() or an iterator.

13. Summary

  • Set is a collection without duplicates and without indexes.
  • HashSet has no order, LinkedHashSet keeps insertion order, TreeSet keeps elements sorted.
  • Hash-based sets rely on equals() and hashCode(); tree sets rely on comparison.
  • addAll, retainAll and removeAll give union, intersection and difference.
  • Set.of() and Set.copyOf() create unmodifiable sets.

Related Tutorials

Reference: Java SE 21 API: java.util.Set