Collections Framework

Sets

A Set rejects duplicates as defined by equals (or compareTo in sorted sets). HashSet is O(1) and unordered, LinkedHashSet remembers insertion order, TreeSet iterates sorted at O(log n) per operation.
  • HashSet: hash table over a backing HashMap; iteration order is arbitrary and can change
  • LinkedHashSet: insertion-ordered iteration for a small memory premium
  • TreeSet: red-black tree, sorted iteration, NavigableSet range queries
  • Elements must have consistent equals/hashCode — and stay unmutated while inside
  • EnumSet for enum elements: bit-vector speed with Set semantics
  • Iteration order: HashSet arbitrary, LinkedHashSet insertion order, TreeSet sorted order
  • Set.of(...) rejects duplicate arguments at construction — throws IllegalArgumentException, not a silent dedup

A Set is best understood as a Map with no values: HashSet is a HashMap<E, Object> sharing one dummy value, and TreeSet wraps a TreeMap. Everything that governs a map — how equals/hashCode decide identity, iteration order, load factor (Hashing Internals) — governs the matching set verbatim. Pick a set the same way you'd pick its map: HashSet for O(1) membership and don't-care order, LinkedHashSet to remember insertion order, TreeSet when you need sorted iteration or range queries.

Deduplication and membership
Set<String> seen = new HashSet<>();
for (String word : words) {
    if (!seen.add(word)) {          // add() returns false for duplicates
        System.out.println("dup: " + word);
    }
}

Set<String> sorted = new TreeSet<>(words);         // sorted, deduped
Set<String> ordered = new LinkedHashSet<>(words);  // first-seen order kept

Set algebra comes from bulk operations: a.retainAll(b) (intersection), a.addAll(b) (union), a.removeAll(b) (difference). For membership-heavy pipelines, Set.contains at O(1) beats List.contains at O(n) — a frequent silent performance bug (Choosing Collections).

TreeSet implements NavigableSet: first(), last(), floor(e), ceiling(e), headSet, tailSet, subSet — range views over the sorted order. Remember membership is decided by compareTo, not equals (Sorted Collections).

Dedup a stream, then navigate a sorted set
record LogEntry(String host, Instant at) {}

Set<String> distinctHosts = entries.stream()
        .map(LogEntry::host)
        .collect(Collectors.toCollection(HashSet::new));   // membership only, order irrelevant

NavigableSet<Integer> ports = new TreeSet<>(Set.of(22, 80, 443, 8080));
ports.ceiling(100);     // 443  — smallest element >= 100
ports.headSet(443);     // [22, 80]  — everything below 443
ports.descendingSet();  // 8080, 443, 80, 22
// ports.contains(443) is O(log n) here; a HashSet would answer the same question in O(1)
// — pay for navigation only when you actually use floor/ceiling/range queries
Sources
  • Core Java, Volume I: Fundamentals (13th ed.)Ch. 9.3 — Concrete Collections
  • Learning Java (6th ed.)Ch. 7 — Collections
  • Effective Java (3rd ed.)Item 36 (EnumSet)