HashSet and TreeSet in Java: Runnable Examples and Key Differences
Learn how Java sets handle duplicates, ordering, navigation and custom objects through deterministic examples you can run and modify.
KnowledgeGate Team
Exam prep & CS education

Both classes reject duplicates, so HashSet and TreeSet can look interchangeable. Ordering, range queries and custom objects expose the difference. A six-value trace shows why equality or a comparator can make add return false. The Coding & DSA Courses for Placements page places these set operations in the wider Java data-structures path.
HashSet and TreeSet: Start with the Shared Set Contract
A Set keeps each distinct element at most once. add reports change, contains tests membership, and remove reports whether the element existed. Insert [42, 7, 42, 19, 7, 31] and both sets finish with four values.
HashSet suits uniqueness and membership without sorted iteration. TreeSet is a NavigableSet: iteration follows natural order or a comparator, and its API answers ordered queries. Oracle documents these contracts for HashSet and TreeSet. For first-insertion order, choose LinkedHashSet.
Fully Worked Example: Insert the Same Values into Both Sets

SetDemo sorts a copied HashSet only when it needs deterministic display.
import java.util.*;
public class SetDemo {
public static void main(String[] args) {
Set<Integer> hashSet = new HashSet<>();
NavigableSet<Integer> treeSet = new TreeSet<>();
int[] values = {42, 7, 42, 19, 7, 31};
for (int value : values) {
boolean hashAdded = hashSet.add(value);
boolean treeAdded = treeSet.add(value);
System.out.printf("add %d -> hash=%s, tree=%s%n",
value, hashAdded, treeAdded);
}
System.out.printf("size -> hash=%d, tree=%d%n",
hashSet.size(), treeSet.size());
System.out.printf("contains 19 -> hash=%s, tree=%s%n",
hashSet.contains(19), treeSet.contains(19));
List<Integer> sortedHashView = new ArrayList<>(hashSet);
Collections.sort(sortedHashView);
System.out.println("HashSet sorted only for display: " + sortedHashView);
System.out.println("TreeSet natural order: " + treeSet);
System.out.printf("remove 42 -> hash=%s, tree=%s%n",
hashSet.remove(42), treeSet.remove(42));
sortedHashView = new ArrayList<>(hashSet);
Collections.sort(sortedHashView);
System.out.println("after removal -> hash=" + sortedHashView
+ ", tree=" + treeSet);
}
}The insertion trace is:
add 42 -> hash=true, tree=true
add 7 -> hash=true, tree=true
add 42 -> hash=false, tree=false
add 19 -> hash=true, tree=true
add 7 -> hash=false, tree=false
add 31 -> hash=true, tree=true
size -> hash=4, tree=4
contains 19 -> hash=true, tree=true
HashSet sorted only for display: [7, 19, 31, 42]
TreeSet natural order: [7, 19, 31, 42]
remove 42 -> hash=true, tree=true
after removal -> hash=[7, 19, 31], tree=[7, 19, 31]The copied list was sorted externally. The second line reflects TreeSet iteration order.

How HashSet Decides That Two Objects Are Duplicates
Hashing narrows the candidate area, then equals decides logical equality. Oracle specifies expected constant time for add, remove and contains, assuming proper hash dispersion. Hashing and Collision Resolution: Chaining vs Probing explains buckets and collisions.
Suppose immutable BuildJob has id, queue and priority, while equals and hashCode use only id:
Set<BuildJob> jobs = new HashSet<>();
jobs.add(new BuildJob(501, "api", 3)); // true
jobs.add(new BuildJob(501, "web", 5)); // false
jobs.add(new BuildJob(702, "worker", 3)); // true
jobs.size(); // 2
jobs.contains(new BuildJob(501, "any", 0)); // trueResults follow from the ID-based rule, not queue names or priorities. Overriding equals without a matching hashCode, or using different fields, makes membership unreliable. Keep identity fields immutable. If an inserted ID changes from 501 to 999, lookup can fail while the object remains inside.
TreeSet Ordering, Navigation and Comparator-Based Uniqueness
For [7, 19, 31, 42], first() is 7, last() is 42, lower(19) is 7, higher(19) is 31, and ceiling(20) is 31. The call subSet(7, true, 31, false) gives [7, 19]: 7 is included and 31 is excluded.
A comparator also defines uniqueness. Consider immutable build records whose equals and hashCode use all three fields:
Comparator<RankedBuild> byDuration =
Comparator.comparingInt(RankedBuild::durationMinutes);Adding (501, api, 18), (502, web, 18) and (503, worker, 27) returns true, false, true. The second comparison produces 0, so TreeSet treats build 502 as a duplicate. Preserve all three with:
Comparator<RankedBuild> completeOrder =
Comparator.comparingInt(RankedBuild::durationMinutes)
.thenComparingInt(RankedBuild::id)
.thenComparing(RankedBuild::module);The order becomes (501, api, 18), (502, web, 18), (503, worker, 27). Make comparison consistent with equals, as Oracle's Comparator contract recommends, or document another uniqueness rule. Java Iterators and Comparators: Runnable Examples, Sorting Rules and Common Traps develops comparator chains and sorting; here, comparison equality matters because compare() == 0 defines membership in a TreeSet. Binary Trees and BSTs: Traversals, Insert, Search, Delete offers tree intuition, not a guaranteed TreeSet shape.
HashSet vs TreeSet Complexity and Choice Table
Question | HashSet | TreeSet |
|---|---|---|
Iteration order | Not guaranteed | Sorted by natural order or comparator |
Duplicate rule | Matching | Comparison result |
Basic operation cost | Expected constant time with good dispersion | Guaranteed logarithmic time |
Navigation and ranges | Not provided |
|
Null behaviour | Permits one | Natural-order use rejects |
Best fit | Membership and uniqueness | Sorted membership and ordered queries |
Use HashSet for processed IDs {205, 101, 310}. Use TreeSet for thresholds {42, 7, 19, 31} when ceiling(20) must return 31. Use LinkedHashSet when iteration must retain 205, 101, 310. Sort a copied hash set for one report; use TreeSet for repeated neighbour or range queries.
Common HashSet and TreeSet Errors, with Corrections
Do not test raw hash output with assertEquals("[7, 19, 31, 42]", hashSet.toString()). Assert size, membership and set equality, or sort a copy. new String("Java") and "Java" collapse into one element because their contents are equal.
Do not stop a comparator at a non-unique field. The duration-only comparator silently rejected build 502, so add tie-breakers for every field needed to distinguish elements. Avoid subtraction comparators too: Integer.MAX_VALUE - (-1) overflows to -2147483648 and can reverse the intended order. Use Integer.compare(a, b) or comparator factories.
Finally, null behaviour differs. HashSet permits one null, while new TreeSet<Integer>().add(null) throws NullPointerException under natural ordering. Validate nulls before inserting into an ordered set.
How Exams and Interviews Test Set Reasoning
After inserting 42, 7, 42, 19, 7, 31, both sizes are 4; duplicate additions return false and false; ceiling(20) returns 31; raw HashSet order is unpredictable. Reason from equality, insertion, ordering, then navigation.
For the custom objects, build 502's add returns false because its duration-only comparison against build 501 returns 0, despite different IDs and modules. The repair is ordering by duration, then ID, then module.
Try these checks before running code:
Insert
[5, 2, 5, 9, 2]. Both sizes are3; tree iteration is[2, 5, 9].For
[10, 20, 30, 40],floor(25)is20,ceiling(25)is30, andsubSet(10, false, 40, false)is[20, 30].Make both
"cat"and"dog"survive a length comparator by chainingthenComparing(Comparator.naturalOrder()). Inputhorse, cat, dogproduces[cat, dog, horse].
Short Version and the Next Java Practice Step
Remember five rules: both sets enforce uniqueness; HashSet relies on equals and hashCode; TreeSet relies on natural or comparator order; comparison result 0 means duplicate to TreeSet; only TreeSet supplies sorted navigation and range views.
Use the Java course to rebuild Core and Advanced Java concepts through MCQs and coding questions. Move to DSA using Java when you want broader implementation and problem-solving practice.
Now rerun SetDemo with [18, 4, 18, 27, 9, 4]. Predict every add result and the final tree [4, 9, 18, 27] before execution. Then revisit hashing for collision mechanics and binary trees for ordered-tree background.
Keep learning
TreeMap and SortedMap in Java: Ordering, Range Views and Worked Examples
Learn how Java's TreeMap orders keys, answers floor and ceiling queries, exposes live range views, and handles comparator collisions through worked examples.
Java Garbage Collection Tutorial: Reachability, Leaks and Runnable Examples
Trace three connected objects, find exactly when each becomes eligible for collection, and repair a cache that keeps byte arrays reachable.
Java Memory Model Tutorial: Happens-Before, volatile and Safe Publication
Learn the Java Memory Model through exact start/join, volatile, synchronized, final-field and AtomicInteger examples, with clear happens-before guarantees.
Java Exception Handling Tutorial with Runnable Examples
Learn how Java moves control through try, catch, and finally, then build checked custom exceptions and safer file handling with runnable code.





