Set Interface

Su Suriya Ravichandran Updated 14 Nov 2026
6 min read ·Lesson 82 of 133

java.util.Set is the interface for collections that contain no duplicate elements. It models the mathematical idea of a set: an element is either in it or not, and adding something already present changes nothing. HashSet, LinkedHashSet, TreeSet, EnumSet, and the immutable sets from Set.of all implement it. This lesson looks at what the interface guarantees, how its implementations differ, and how to use sets for membership checks and set algebra.

What the Set Contract Guarantees

PropertyMeaning
No duplicatesAt most one element e for which e.equals(x) is true (or, for sorted sets, compare(e, x) == 0)
At most one nullIf the implementation allows null at all
No indexThere is no get(int); elements are accessed by membership or iteration
OrderNot part of the base contract: depends on the implementation

Set adds no new methods to Collection. What it changes is the meaning of existing ones:

  • add(e) returns false and leaves the set unchanged if e is already present.
  • equals returns true for any two sets containing the same elements, regardless of implementation or order.
  • hashCode is the sum of the elements' hash codes, so equal sets have equal hash codes.
Set<Integer> a = Set.of(1, 2, 3);
Set<Integer> b = new TreeSet<>(List.of(3, 2, 1));
System.out.println(a.equals(b));    // true: same elements, order and class irrelevant

The Set Family

Collection
  └── Set
        ├── HashSet               hash table, no order
        │     └── LinkedHashSet   + insertion order       (SequencedSet, Java 21)
        ├── SortedSet
        │     └── NavigableSet
        │           └── TreeSet   red-black tree, sorted
        ├── EnumSet               bit vector for enum constants
        └── CopyOnWriteArraySet, ConcurrentSkipListSet (concurrent)
ImplementationOrderadd / containsNotes
HashSetNone guaranteedO(1) averageGeneral default
LinkedHashSetInsertion orderO(1) averagePredictable output; deduplicate while keeping order
TreeSetSortedO(log n)first, floor, ranges; needs ordering
EnumSetEnum declaration orderO(1)Extremely compact and fast; enum elements only
Set.of(...)UnspecifiedO(1)Immutable; no null; duplicates in arguments throw
ConcurrentSkipListSetSortedO(log n)Thread-safe sorted set

Programming to the Set Interface

Set<String> tags = new HashSet<>();

public boolean hasAll(Set<String> granted, Set<String> required) {
    return granted.containsAll(required);
}

As with List, declare variables and parameters as Set so the implementation can change. Use SortedSet or NavigableSet as the declared type when the code depends on ordering methods such as first() or ceiling(), and SequencedSet (Java 21) when it depends on a defined encounter order with getFirst(), getLast(), or reversed().

Membership: The Core Use Case

The reason to use a set is fast, duplicate-free membership:

Set<String> blocked = Set.of("spam@example.com", "bot@example.com");

if (blocked.contains(email)) {
    reject();
}

With a List, contains scans every element; with a hash set, it examines one bucket. For checks repeated thousands of times, such as filtering a large data stream against a blocklist, the difference is enormous.

Set Algebra

The bulk methods inherited from Collection perform the classic set operations. They modify the set they are called on, so copy first when the original must stay unchanged:

Mathematical operationCodeResult
Union A ∪ Ba.addAll(b)Elements in either
Intersection A ∩ Ba.retainAll(b)Elements in both
Difference A − Ba.removeAll(b)Elements in A but not B
Subset B ⊆ Aa.containsAll(b)true if every element of B is in A
DisjointCollections.disjoint(a, b)true if they share no elements
Set<String> javaStudents = Set.of("ada", "grace", "alan");
Set<String> sqlStudents = Set.of("grace", "linus");

Set<String> both = new HashSet<>(javaStudents);
both.retainAll(sqlStudents);                         // [grace]

Set<String> eitherCourse = new HashSet<>(javaStudents);
eitherCourse.addAll(sqlStudents);                    // ada, grace, alan, linus

Set<String> javaOnly = new HashSet<>(javaStudents);
javaOnly.removeAll(sqlStudents);                     // ada, alan

boolean noOverlap = Collections.disjoint(javaStudents, Set.of("linus"));   // true

Immutable Sets

Set<String> weekend = Set.of("SAT", "SUN");
Set<String> snapshot = Set.copyOf(mutableSet);

Set.of and Set.copyOf create unmodifiable sets that:

  • throw UnsupportedOperationException on add, remove, or clear,
  • reject null elements with NullPointerException,
  • (for Set.of) throw IllegalArgumentException if the arguments contain duplicates,
  • have no defined iteration order, which may even vary between runs of the program.

Set.copyOf silently drops duplicates, so it is the right way to make an immutable set from data that may repeat. Collections.unmodifiableSet(set) instead returns a read-only view that reflects later changes to the underlying set.

EnumSet

When the elements are constants of a single enum, EnumSet is the best implementation. It stores membership as bits in a long, making every operation fast and memory use tiny:

enum Day { MON, TUE, WED, THU, FRI, SAT, SUN }

Set<Day> weekend = EnumSet.of(Day.SAT, Day.SUN);
Set<Day> weekdays = EnumSet.complementOf(EnumSet.copyOf(weekend));
Set<Day> midweek = EnumSet.range(Day.TUE, Day.THU);
Set<Day> none = EnumSet.noneOf(Day.class);
Set<Day> all = EnumSet.allOf(Day.class);

EnumSet iterates in the enum's declaration order and is the modern replacement for integer bit flags (READ | WRITE).

Requirements on Elements

The set implementation determines how duplicates are detected:

  • Hash-based sets (HashSet, LinkedHashSet) use hashCode and equals. Elements must implement both consistently.
  • Sorted sets (TreeSet) use compareTo or a Comparator. Elements that compare as 0 are duplicates, even if equals says otherwise.
  • In every case, elements should be immutable, or at least must not change in ways that affect equality, hashing, or ordering while they are in the set.

Records, strings, wrapper types, enums, and java.time types all meet these requirements out of the box.

Converting Between Lists and Sets

List<String> withDupes = List.of("b", "a", "b", "c", "a");

Set<String> unique = new HashSet<>(withDupes);              // no order
Set<String> uniqueOrdered = new LinkedHashSet<>(withDupes); // [b, a, c]
Set<String> uniqueSorted = new TreeSet<>(withDupes);        // [a, b, c]

List<String> backToList = new ArrayList<>(uniqueOrdered);   // [b, a, c]
List<String> viaStream = withDupes.stream().distinct().toList();   // [b, a, c]

stream().distinct() also keeps the first occurrence of each element in encounter order.

Choosing a Set

NeedUse
Fast membership, order irrelevantHashSet
Remove duplicates but keep first-seen orderLinkedHashSet
Sorted iteration, nearest-value or range queriesTreeSet
Elements are enum constantsEnumSet
Fixed set of constants or a returned snapshotSet.of / Set.copyOf
Shared between threadsConcurrentHashMap.newKeySet(), ConcurrentSkipListSet

Practical Example: Role-Based Permissions

Users can hold several roles, and each role grants a set of permissions. A user's effective permissions are the union of their roles' permissions; an action is allowed only if the user holds every permission it requires.

import java.util.*;

public class Permissions {
    enum Perm { READ, WRITE, DELETE, PUBLISH, MANAGE_USERS }

    static final Map<String, Set<Perm>> ROLES = Map.of(
        "viewer", EnumSet.of(Perm.READ),
        "editor", EnumSet.of(Perm.READ, Perm.WRITE, Perm.PUBLISH),
        "admin",  EnumSet.allOf(Perm.class)
    );

    static Set<Perm> effective(Collection<String> roles) {
        Set<Perm> result = EnumSet.noneOf(Perm.class);
        for (String r : roles) {
            result.addAll(ROLES.getOrDefault(r, Set.of()));
        }
        return result;
    }

    public static void main(String[] args) {
        Set<Perm> user = effective(List.of("viewer", "editor"));
        System.out.println("Effective:    " + user);

        Set<Perm> needed = EnumSet.of(Perm.WRITE, Perm.DELETE);
        System.out.println("Can do all?   " + user.containsAll(needed));

        Set<Perm> missing = EnumSet.copyOf(needed);
        missing.removeAll(user);
        System.out.println("Missing:      " + missing);

        Set<Perm> adminOnly = EnumSet.complementOf(EnumSet.copyOf(user));
        System.out.println("Admin-only:   " + adminOnly);

        System.out.println("Same as editor? " + user.equals(ROLES.get("editor")));
    }
}

Output:

Effective:    [READ, WRITE, PUBLISH]
Can do all?   false
Missing:      [DELETE]
Admin-only:   [DELETE, MANAGE_USERS]
Same as editor? true

Every operation here is a set operation. addAll computes the union of the user's roles, and because sets ignore duplicates, READ appears once even though two roles grant it. containsAll is the subset test that decides whether an action is allowed, and removeAll on a copy computes exactly which permissions are missing, which makes for useful error messages. EnumSet keeps the output in the enum's declaration order and makes each operation a fast bitwise computation. The final line shows the Set equality contract: the computed set equals the editor role's set because they contain the same elements, regardless of how each was built.

0 Comments

Reviewed before they appear

No comments yet.

Java
Java Introduction Java Features Java Syntax Java Comments Java Statements Java Output Java Variables Java Data Types Java Type Casting Java Operators Java Strings Java Numbers Java Math Java Booleans Java User Input Java Conditions Java If Else Java Switch Java While Loop Java For Loop Java Break Java Continue Java Arrays Java Methods Java Parameters Java Return Values Java Scope Java Recursion Install Java Install JDK Java IDEs Java JDK Java JRE Java JVM Java Compiler Java File Compile Java Run Java JShell Basics Java Packages Java OOP Java Classes Java Objects Class Methods Constructors Constructor Overload this Keyword static Keyword final Keyword Encapsulation Inheritance Polymorphism Abstraction Access Modifiers super Keyword Method Overload Method Override Instanceof Operator Nested Classes Inner Classes Anonymous Classes Enums Records Array Basics Array Length Loop Arrays Multidimensional Arrays Array Copy Array Sorting Array Search ArrayList LinkedList HashSet TreeSet HashMap TreeMap Queue Interface Deque Interface Stack Class Iterator List Interface Set Interface Map Interface Collections Class Comparable Comparator Generics Basics Generic Classes Generic Methods Wildcards String Basics String Length String Methods String Concatenation String Compare String Search String Replace String Split String Format StringBuilder StringBuffer Text Blocks Regular Expressions Number Types Integer Class Float Class Double Class BigInteger BigDecimal Math Class Random Numbers Number Format Date Basics LocalDate LocalTime LocalDateTime ZonedDateTime Date Formatting Date Parsing Period Class Duration Class Java Instant Class Java Exception Basics Java try...catch Java Multiple Catch Blocks Java finally Block Java throw Keyword Java throws Keyword Java Checked Exceptions Java Unchecked Exceptions Java Custom Exceptions Java try-with-resources Java Exception Chaining
Ask about this post
AI Ask about this post

Ask questions about Set Interface and get answers drawn from it.

Signed-in readers only.