skip to content

Set Implementations

Collections that enforce uniqueness through equals and hashCode, differing in whether they keep no order, insertion order, or sorted order. Interviewers use them to revisit the equals/hashCode contract from the collection side.

part ofJavaoverview, primer and where to startread it →
on this pageshow

explore

questions

15

What is a HashSet in Java and what guarantees does it provide about element ordering and uniqueness?

level: juniorimportance: must knowfreq 78%

answer

  1. Backed by a HashMap, element = key, value = shared dummy
  2. No ordering guarantee; order can change on rehash
  3. Average O(1) add/remove/contains
  4. Uniqueness via equals() + hashCode()
  5. Allows one null

basics

~10 s

A HashSet is a collection that stores unique elements with no duplicates. It does not keep elements in any particular order, and you cannot rely on the order when you iterate over it.

solid answer

~40 s

A HashSet is Java's implementation of the Set interface that stores unique elements. It is backed internally by a HashMap: each element you add becomes a key in that map, with a shared dummy object as the value, so duplicate keys (elements) are silently rejected. Because of this, add, remove, and contains run in average O(1) time. HashSet gives no ordering guarantee at all: the iteration order depends on hash codes and the internal bucket layout, and it can change as the set grows and rehashes. It permits a single null element. If you need predictable iteration you reach for LinkedHashSet (insertion order) or TreeSet (sorted order). Uniqueness is decided by the elements' equals() and hashCode() methods, not by reference identity.

code

java · 9 lines
java
Set<String> fruits = new HashSet<>();
fruits.add("apple");
fruits.add("banana");
fruits.add("apple"); // duplicate, ignored

System.out.println(fruits.size());          // 2
System.out.println(fruits.contains("apple")); // true (average O(1))
// Iteration order is unspecified — do NOT rely on it:
for (String f : fruits) System.out.println(f);

go deeper

for a junior

Knows HashSet stores unique elements with no guaranteed order and offers fast lookups.

for a middle

Can explain it is backed by a HashMap (element as key), the average O(1) operations, and the single-null rule.

for a senior

Articulates the hashCode/equals bucket mechanism, rehashing's effect on order, and the worst-case collision behaviour.

for a principal

Reasons about memory/throughput trade-offs versus other Set impls and when iteration-order or sorted semantics justify a different structure across a codebase's conventions.

## What problem a Set solves A **Set** is a collection that holds **no duplicate elements** — like the mathematical idea of a set. If you try to add something that is already there, nothing changes. This is different from a **List**, which allows duplicates and keeps a positional order. Java's `java.util.Set` is an interface (a contract). `HashSet` is the most common concrete class that fulfils that contract. ## How HashSet actually works inside HashSet does not invent its own storage. It **wraps a `HashMap`**. A HashMap stores **key → value** pairs and guarantees the keys are unique. HashSet exploits that: when you call `set.add("apple")`, internally it does `map.put("apple", PRESENT)`, where `PRESENT` is a single shared dummy `Object` reused for every entry (so it wastes no extra memory per element). The element you care about is stored as the **key**; the value is throwaway. Because HashMap keys are unique, HashSet elements are automatically unique — HashSet inherits uniqueness for free. ## Hashing in one paragraph A **hash code** is an `int` produced by an object's `hashCode()` method. The map uses it to decide which **bucket** (slot in an internal array) the element lands in: roughly `bucketIndex = hash & (arrayLength - 1)`. Many objects can share a bucket (a **collision**); within a bucket they are compared with `equals()`. So: - `hashCode()` finds the bucket quickly. - `equals()` confirms exact identity within that bucket. This two-step lookup is why `contains`, `add`, and `remove` are **average O(1)** — constant time, independent of the set's size — instead of scanning every element. ## Ordering: the key takeaway HashSet gives **no ordering guarantee**. The order you see when iterating is an artefact of hash codes and bucket placement, and it can change when the set **rehashes** (rebuilds its internal array as it grows). Never write code that depends on HashSet iteration order. ## Nulls HashSet permits exactly **one `null`** element (because HashMap permits one null key). ## When to use it Reach for HashSet when you need fast membership tests and de-duplication and you do **not** care about order. If you need insertion order, use `LinkedHashSet`; if you need sorted order, use `TreeSet`.

  • Why does HashSet allow only one null element?
    Because it is backed by a HashMap, which permits a single null key. The null is hashed to bucket 0 by special-case handling. A second null would be a duplicate key and is ignored.
  • What is the time complexity of contains() on a HashSet and why?
    Average O(1): hashCode() picks a bucket directly and equals() checks the few elements in that bucket. Worst case is O(n) if all elements collide into one bucket, though modern HashMap turns long collision chains into balanced trees, bounding it to O(log n).

Think of a coat-check room with numbered hooks. The hash code tells you which hook to go to instantly; if two coats share a hook you compare them by hand (equals). You never get your coats back in the order you handed them in.

saying these in an interview costs you the question

  • Claiming HashSet preserves insertion order
  • Saying HashSet is sorted (that's TreeSet)
  • Believing add/contains are O(n) in the common case
  • Thinking uniqueness is based on == reference equality rather than equals()/hashCode()

context

open as a page

What is a Set in Java, and how does it decide that two elements are duplicates?

level: juniorimportance: must knowfreq 78%

basics

~10 s

A 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.

open as a page

What is a TreeSet in Java, and how does it differ from a HashSet?

level: juniorimportance: must knowfreq 75%

basics

~10 s

A TreeSet is a Set that keeps its elements automatically sorted. A HashSet stores elements in no particular order but is faster. Use TreeSet when you need the elements in order.

open as a page

What is the difference between HashSet and LinkedHashSet, and when would you choose one over the other?

level: middleimportance: must knowfreq 70%

basics

~10 s

Both store unique elements. HashSet has no defined iteration order, while LinkedHashSet remembers the order you added items and iterates them in that insertion order. Choose LinkedHashSet when order matters.

open as a page

Explain the equals/hashCode contract and why violating it breaks a HashSet.

level: middleimportance: must knowfreq 85%

basics

~10 s

If two objects are equal by equals(), they must return the same hashCode(). If you break this, a HashSet can store duplicates or fail to find elements you put in.

open as a page

How does a TreeSet know how to order its elements, and what happens if it can't compare them?

level: middleimportance: must knowfreq 70%

basics

~10 s

It orders elements either by their natural ordering (the type implements Comparable) or by a Comparator you pass to the constructor. If neither exists, adding an element throws a ClassCastException.

open as a page

Why must you correctly override both equals() and hashCode() for objects stored in a HashSet, and what breaks if you don't?

level: seniorimportance: must knowfreq 74%

basics

~10 s

A HashSet uses hashCode() to find an element's bucket and equals() to confirm a match. If your objects don't override both consistently, the set can store duplicates or fail to find items you added.

open as a page

Is HashSet thread-safe, and how do you safely share a set of unique elements across multiple threads?

level: middleimportance: should knowfreq 52%

basics

~10 s

No, HashSet is not thread-safe. If several threads modify it at once you can corrupt it or get errors. Use a concurrent set or external synchronization to share one safely.

open as a page

What goes wrong when you put mutable objects into a HashSet and then change them, and how do you avoid it?

level: middleimportance: should knowfreq 50%

basics

~20 s

If you change a field that affects an element's hashCode/equals after adding it, the HashSet may no longer find it — contains and remove can fail even though the object is still inside. Use immutable elements.

open as a page

Explain the NavigableSet navigation methods (floor, ceiling, lower, higher) and how they differ.

level: middleimportance: should knowfreq 60%

basics

~20 s

They find the nearest element to a given value. ceiling returns the smallest element >= the value; floor the largest <= it; higher is strictly greater; lower is strictly less. They return null if no such element exists.

open as a page

How do initial capacity and load factor affect a HashSet's performance, and how would you size one for a known number of elements?

level: seniorimportance: should knowfreq 48%

basics

~20 s

A HashSet has internal buckets. As it fills past a threshold it grows and rehashes, which is costly. If you know how many items you'll add, give it a starting capacity so it avoids repeated resizing.

open as a page

What is CopyOnWriteArraySet and how does its copy-on-write mechanism work?

level: seniorimportance: should knowfreq 55%

basics

~10 s

CopyOnWriteArraySet is a thread-safe Set backed by a CopyOnWriteArrayList. Reads are lock-free, but every write copies the whole underlying array, so it suits small, read-heavy sets.

open as a page

When would you choose a TreeSet over a HashSet or a PriorityQueue, and what are the costs?

level: seniorimportance: should knowfreq 55%

basics

~20 s

Use a TreeSet when you need elements kept sorted and need to query ranges or nearest values. It is slower (O(log n)) and uses more memory than a HashSet, and unlike a PriorityQueue it has no duplicates and lets you search and iterate in full order.

open as a page

What do headSet, tailSet, and subSet return, and what does it mean that they are 'views'?

level: seniorimportance: should knowfreq 50%

basics

~20 s

They return a portion of the TreeSet within a range: headSet is everything below a value, tailSet everything from a value up, subSet a range between two. They are live views, so changes to either the view or the original affect both.

open as a page

How do you choose between CopyOnWriteArraySet, ConcurrentHashMap.newKeySet, and Collections.synchronizedSet for a thread-safe Set?

level: principalimportance: should knowfreq 48%

basics

~10 s

Pick by read/write ratio and size. CopyOnWriteArraySet for tiny read-mostly sets, ConcurrentHashMap.newKeySet for large or write-heavy concurrent sets, and synchronizedSet only as a simple fallback that locks every operation.

open as a page