🗃️ Collections Framework · Intermediate

HashSet, LinkedHashSet, TreeSet in Java

No order, insertion order, sorted order.

🧩 The mysteryAdd "pear", "apple", "pear" to three different Sets. You get three different printouts, and one of them might change if you upgrade Java. Which one, and why?

One rule: no duplicates

Every Set rejects duplicates (judged by equals). **add() returns false** when the element was already there and true when the set actually changed. That makes duplicate detection a one-liner.

Set<String> seen = new HashSet<>();
if (!seen.add(word)) {
    System.out.println("dup: " + word);
}

Three ordering personalities

**HashSet: no guaranteed order, fastest (O(1) average). LinkedHashSet: remembers insertion order, nearly as fast. TreeSet: keeps elements sorted**, O(log n).

new HashSet<>();       // any order
new LinkedHashSet<>(); // arrival order
new TreeSet<>();       // sorted order
🔮 Predict it

Your turn

What does this print?

Set<String> s = new LinkedHashSet<>();
s.add("kiwi");
s.add("fig");
s.add("kiwi");
System.out.println(s + " " + s.size());
  1. [fig, kiwi] 2
  2. [kiwi, fig] 2
  3. [kiwi, fig, kiwi] 3
Show the answer

The second "kiwi" is a duplicate, so it's ignored and doesn't move anything. LinkedHashSet keeps arrival order: kiwi, then fig. Size 2.

TreeSet can navigate

Because it's sorted, a TreeSet answers neighbour questions: first() (smallest), last(), **ceiling(x) = smallest element ≥ x**, floor(x) = largest ≤ x, and headSet(x) = everything below x.

var t = new TreeSet<>(List.of(40, 10, 30, 20));
// t is [10, 20, 30, 40]
t.first();    // 10
t.ceiling(25);// 30
t.floor(25);  // 20
🔮 Predict it

Sorting what can't be sorted

Pt doesn't implement Comparable. What happens?

record Pt(int x) {}
void main() {
    Set<Pt> s = new TreeSet<>();
    s.add(new Pt(1));
    System.out.println(s);
}
  1. Prints [Pt[x=1]]
  2. Compile error
  3. Throws ClassCastException
Show the answer

It compiles (TreeSet doesn't demand Comparable at compile time) but the first add must compare elements, casts Pt to Comparable, and fails at runtime with **ClassCastException**. Fix: implement Comparable or pass a Comparator.

⚠️ The trap

Trusting HashSet's order

A HashSet may *look* sorted for small numbers, but the order is an accident of hashing. It can change when the set resizes or between Java versions. If order matters to your output or tests, use LinkedHashSet or TreeSet.

💼 In the real world

Picking the right Set

Dedupe user IDs fast? HashSet. Keep tags in the order a user typed them? LinkedHashSet. Show a leaderboard or find "the next free time slot after 14:00"? TreeSet with ceiling. Choosing well removes whole sorting steps from your code.

Key takeaways

  1. HashSet: no guaranteed order, O(1) average add/contains
  2. LinkedHashSet: insertion order, nearly as fast
  3. TreeSet: sorted order, O(log n), needs Comparable or a Comparator
  4. add() returns false when the element is already present

💡 HashSet is a bag of marbles, LinkedHashSet is a queue of people in arrival order, TreeSet is a bookshelf sorted alphabetically.

🤯 Did you know?

HashSet is built on a HashMap: each element is stored as a key, and every key shares one dummy value object. Peek at the OpenJDK source and you'll find it named PRESENT.

Practice questions

What does this print?

Set<String> s = new LinkedHashSet<>();
s.add("pear");
s.add("apple");
s.add("pear");
System.out.println(s + " " + s.size());
  1. [apple, pear] 2
  2. [pear, apple] 2
  3. [pear, apple, pear] 3
  4. [pear, apple] 3
Check your answer

[pear, apple] 2. The second "pear" is a duplicate, so it's ignored. LinkedHashSet keeps the original insertion order: pear first, then apple.

What does this print?

var set = new TreeSet<>(List.of(5, 1, 9, 3));
System.out.println(set);
System.out.println(set.first());
System.out.println(set.ceiling(4));
  1. [1, 3, 5, 9] 1 5
  2. [5, 1, 9, 3] 5 9
  3. [1, 3, 5, 9] 1 3
  4. [9, 5, 3, 1] 9 5
Check your answer

[1, 3, 5, 9] 1 5. TreeSet sorts elements naturally. first() is the smallest, and ceiling(4) is the smallest element ≥ 4, which is 5.

Next: Maps work like Sets with a value attached to each key. What does put return when the key is already taken?