What is a Set in Java, and how does it decide that two elements are duplicates?
answer
- No duplicates — mathematical set
- Duplicate decided by equals() (TreeSet: compareTo==0)
- add returns false if already present
- HashSet uses hashCode to find bucket
- HashSet/LinkedHashSet/TreeSet variants
basics
~10 sA Set is a collection that holds no duplicate elements. When you add an element, the Set checks the ones already stored; if an equal one exists, the new element is not added.
solid answer
~40 sA Set models the mathematical idea of a set: each distinct value is stored at most once, and duplicates are rejected. The Set does not invent its own notion of sameness; it delegates to the elements via equals() (and, for hash-based sets, hashCode() first). When you call add(x), the Set looks for an existing element e where x.equals(e); if found, add returns false and nothing changes, otherwise x is stored and add returns true. So a Set never holds two elements a and b with a.equals(b). Common implementations are HashSet (unordered, fast, uses hashCode/equals), LinkedHashSet (keeps insertion order), and TreeSet (sorted, uses compareTo/Comparator). Sets are ideal for membership tests and de-duplication.
code
java · 9 linesSet<String> names = new HashSet<>();
System.out.println(names.add("Bob")); // true (added)
System.out.println(names.add("Bob")); // false (duplicate, ignored)
System.out.println(names.size()); // 1
System.out.println(names.contains("Bob")); // true
// De-duplicate a list in one line:
List<Integer> nums = List.of(1, 2, 2, 3, 3, 3);
Set<Integer> unique = new HashSet<>(nums); // {1, 2, 3}go deeper
Knows a Set rejects duplicates and that equals() decides sameness; can name HashSet and use add/contains.
Explains the role of hashCode in HashSet bucketing, distinguishes the three implementations and their ordering, and uses add's boolean return.
Connects uniqueness to the equals/hashCode contract, contrasts equals-based vs comparator-based uniqueness (TreeSet), and warns about mutable elements breaking lookups.
Reasons about choosing Set implementations for performance/memory trade-offs and API design (returning Set to express a uniqueness invariant), and the consequences of weak hash distribution at scale.
## What problem a Set solves Imagine a guest list where the same person must never appear twice. In Java the type that guarantees this is the **`Set`** interface (package `java.util`). A `Set` is a *collection* (an object holding many elements) with one defining rule: it contains **no duplicate elements**. ## What "duplicate" means A `Set` does not invent its own idea of sameness; it asks the **elements** through a method named **`equals`**. Every Java object inherits `equals` from the base class `Object`. By default `equals` does *reference equality*: two references are equal only if they point to the very same object in memory (`a == b`). Classes that represent a *value* (like `String`, `Integer`, or your own `Money`) usually **override** `equals` to compare *contents* instead. So whether two objects count as duplicates depends entirely on how their class defines `equals`. ## How adding works When you call `set.add(x)`: 1. The Set searches its existing elements for one, `e`, where `x.equals(e)` is `true`. 2. If such an `e` exists, `add` does **nothing** and returns `false` (the Set already has that value). 3. Otherwise `x` is stored and `add` returns `true`. This is why a `Set` never holds two elements `a` and `b` for which `a.equals(b)`. ## Hash-based sets need hashCode too The most common implementation, **`HashSet`**, would be slow if it compared `x` against *every* element. Instead it groups elements into "buckets" using each element's **`hashCode()`** (an `int` summary of the object). On `add`, `HashSet` computes `x.hashCode()`, jumps straight to the matching bucket, and only calls `equals` on the few elements there. This makes add/contains run in roughly **constant time** O(1) on average. The catch: `hashCode` and `equals` must agree (the *contract*) — see the dedicated question. ## The three everyday implementations - **`HashSet`** — no defined order, fastest, uses `hashCode`/`equals`. - **`LinkedHashSet`** — same speed class but remembers **insertion order** when you iterate. - **`TreeSet`** — keeps elements **sorted**; it decides duplicates by `compareTo`/`Comparator` returning 0, *not* by `equals`. ## Why you'd use a Set - **De-duplication**: `new HashSet<>(listWithDuplicates)` removes repeats. - **Fast membership tests**: `set.contains(x)` is O(1) for `HashSet`, far faster than scanning a `List`. - **Set algebra**: `addAll` (union), `retainAll` (intersection), `removeAll` (difference). ## A subtle gotcha If you put a **mutable** object into a `HashSet` and then change a field that affects its `hashCode`/`equals`, the Set may "lose" it — `contains` returns false even though it's still inside, because it now hashes to a different bucket. Prefer immutable elements.
- What does Set.add return, and why is that useful?It returns true if the element was actually added (was not present) and false if an equal element already existed. You can use the boolean to detect duplicates without a separate contains() call.
- If you need predictable iteration order, which Set do you pick?LinkedHashSet for insertion order, or TreeSet for sorted order. Plain HashSet gives no order guarantee and the order can even change across JVM runs or resizes.
A Set is a guest list: write each name once. The bouncer (equals) decides if 'Bob Smith' is already on the list before letting another in.
saying these in an interview costs you the question
- Saying a Set keeps elements in the order you added them — only LinkedHashSet/TreeSet do; HashSet does not.
- Thinking duplicates are detected by == reference equality rather than equals().
- Claiming TreeSet uses equals() for uniqueness — it uses compareTo/Comparator returning 0.
- Believing add throws or replaces on a duplicate — it silently returns false and leaves the Set unchanged.