HashSet & LinkedHashSet
IntermediateStore unique elements with O(1) lookup using HashSet, or preserve insertion order with LinkedHashSet — both backed by the corresponding Map.
Overview
HashSet implements Set by wrapping a HashMap internally — each element is a key in the map, mapped to a dummy value. This means HashSet inherits all of HashMap's performance characteristics: O(1) add, remove, and contains on average, no guaranteed order. LinkedHashSet wraps a LinkedHashMap instead, maintaining insertion order while still providing O(1) operations. Set semantics mean no duplicate elements — equality is determined by equals() and hashCode().
HashSet — Core Operations & Internal Structure
add(E) returns true if the element was newly added, false if it was already present. contains(Object) is O(1) average — this is HashSet's biggest advantage over ArrayList.contains() which is O(n).
Since HashSet is backed by HashMap, all HashMap caveats apply: equals() and hashCode() must be consistent, and performance degrades if hashCode() is poorly implemented (all elements hash to the same bucket).
import java.util.*;
public class HashSetDemo {
public static void main(String[] args) {
Set<String> set = new HashSet<>();
// add() returns true on new element, false on duplicate
System.out.println(set.add("apple")); // true
System.out.println(set.add("banana")); // true
System.out.println(set.add("apple")); // false — already present
System.out.println(set.size()); // 2
// contains — O(1) average (vs ArrayList O(n))
System.out.println(set.contains("banana")); // true
System.out.println(set.contains("cherry")); // false
// Remove
set.remove("banana");
System.out.println(set); // [apple] — order not guaranteed
// Bulk operations
Set<Integer> a = new HashSet<>(Set.of(1, 2, 3, 4, 5));
Set<Integer> b = new HashSet<>(Set.of(3, 4, 5, 6, 7));
// Union
Set<Integer> union = new HashSet<>(a);
union.addAll(b);
System.out.println(union); // [1, 2, 3, 4, 5, 6, 7]
// Intersection
Set<Integer> intersection = new HashSet<>(a);
intersection.retainAll(b);
System.out.println(intersection); // [3, 4, 5]
// Difference (a - b)
Set<Integer> diff = new HashSet<>(a);
diff.removeAll(b);
System.out.println(diff); // [1, 2]
// Subset check
System.out.println(b.containsAll(Set.of(3, 4))); // true
}
}LinkedHashSet — Insertion Order
LinkedHashSet extends HashSet and wraps a LinkedHashMap. Every element is stored with a doubly-linked pointer connecting it to the previously inserted element. This adds a small memory and time overhead but guarantees that iteration returns elements in the order they were inserted.
Use LinkedHashSet when you need both uniqueness and predictable iteration order — for example, preserving the order of a de-duplicated list.
import java.util.*;
public class LinkedHashSetDemo {
public static void main(String[] args) {
// HashSet — no guaranteed order
Set<String> hashSet = new HashSet<>(List.of("banana", "apple", "cherry"));
System.out.println(hashSet); // [cherry, apple, banana] — unpredictable
// LinkedHashSet — insertion order guaranteed
Set<String> linkedSet = new LinkedHashSet<>(List.of("banana", "apple", "cherry"));
System.out.println(linkedSet); // [banana, apple, cherry] — always insertion order
// De-duplicate a list while preserving order
List<String> withDups = List.of("c", "a", "b", "a", "c", "d");
Set<String> unique = new LinkedHashSet<>(withDups);
List<String> deduped = new ArrayList<>(unique);
System.out.println(deduped); // [c, a, b, d] — first occurrences, in order
// Practical: track visited URLs in order
Set<String> visited = new LinkedHashSet<>();
String[] urls = {"/home", "/products", "/home", "/about", "/products"};
for (String url : urls) visited.add(url);
System.out.println(visited);
// [/home, /products, /about] — duplicates removed, order preserved
// Convert back to List for indexed access
List<String> visitedList = new ArrayList<>(visited);
System.out.println(visitedList.get(1)); // /products
}
}equals() & hashCode() Contract for Sets
For Set to work correctly, elements must implement equals() and hashCode() consistently: 1. If a.equals(b) → a.hashCode() == b.hashCode() (required) 2. If a.hashCode() == b.hashCode() → a.equals(b) may be true or false (collision)
Mutating an object after adding it to a HashSet can break the set — the element lands in the wrong bucket and the set can no longer find it. Never mutate fields that contribute to hashCode() while the object is in a Set or as a Map key.
import java.util.*;
public class SetContractDemo {
static class Point {
int x, y;
Point(int x, int y) { this.x = x; this.y = y; }
@Override public boolean equals(Object o) {
return o instanceof Point p && p.x == x && p.y == y;
}
@Override public int hashCode() { return Objects.hash(x, y); }
@Override public String toString() { return "(" + x + "," + y + ")"; }
}
public static void main(String[] args) {
Set<Point> points = new HashSet<>();
Point p = new Point(1, 2);
points.add(p);
System.out.println(points.contains(new Point(1, 2))); // true — equals
System.out.println(points.contains(new Point(1, 2))); // true
// DANGER: mutate key after adding to set
p.x = 99; // changes hashCode — point now in wrong bucket
System.out.println(points.contains(p)); // false — lost!
System.out.println(points.contains(new Point(99,2)));// false — lost!
System.out.println(points.size()); // 1 — it's still there...
System.out.println(points); // [(99,2)] — in wrong bucket
// Moral: use immutable objects as Set elements / Map keys
record ImmutablePoint(int x, int y) {}
Set<ImmutablePoint> safePoints = new HashSet<>();
safePoints.add(new ImmutablePoint(1, 2));
System.out.println(safePoints.contains(new ImmutablePoint(1, 2))); // true — safe
}
}Interactive Visualization
Key Points to Remember
- HashSet is backed by HashMap — O(1) add/remove/contains; no guaranteed order
- LinkedHashSet is backed by LinkedHashMap — same O(1) performance, insertion order preserved
- add() returns false (not an exception) when a duplicate is detected
- Set operations: addAll (union), retainAll (intersection), removeAll (difference)
- Never mutate fields used in hashCode() while an object is stored in a Set or as a Map key
- Use LinkedHashSet to de-duplicate a list while preserving the order of first appearances
Practice HashSet & LinkedHashSet in the Playground
Run and modify code directly in your browser - no setup needed.
Interview Questions
Sign in to ask AriaWhat is the internal implementation of HashSet in Java?
What is the difference between HashSet and LinkedHashSet?
What happens if you add an object to a HashSet and then mutate it?
How do you find the union and intersection of two Sets in Java?
Why should you override both hashCode() and equals() for Set elements?
Ask Aria about HashSet & LinkedHashSet
Your personal AI tutor — ask anything about this concept