Java course menu
Java HashSet and TreeSet: Unique Elements, Set Operations and Sorted Sets
Learn Java sets: HashSet for fast unique elements, add returning false for duplicates, contains, removing duplicates from a list, union, intersection and difference with addAll, retainAll and removeAll, LinkedHashSet for insertion order, and TreeSet for sorted elements and range queries.
On this page
A set holds unique elements: adding something that is already present has no effect. Sets answer "have I seen this before?" instantly, and they are the easiest way to remove duplicates. Java's main implementations are HashSet (fast, no order), LinkedHashSet (keeps insertion order) and TreeSet (keeps elements sorted).
HashSet basics#
import java.util.HashSet;
import java.util.Set;
public class Main {
public static void main(String[] args) {
Set<String> visited = new HashSet<>();
System.out.println(visited.add("Pune")); // true: new element
System.out.println(visited.add("Delhi"));
System.out.println(visited.add("Pune")); // false: already present
System.out.println(visited.size());
System.out.println(visited.contains("Delhi") + " " + visited.contains("Goa"));
visited.remove("Delhi");
System.out.println(visited);
}
}true
true
false
2
true false
[Pune]add returns false for a duplicate, which makes duplicate detection a one-liner. contains, add and remove are O(1) on average, compared with O(n) for List.contains.
Detecting and removing duplicates#
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
public class Main {
public static void main(String[] args) {
List<Integer> ids = List.of(104, 221, 357, 221, 489, 104);
Set<Integer> seen = new HashSet<>();
for (int id : ids) {
if (!seen.add(id)) {
System.out.println("duplicate: " + id);
}
}
List<Integer> unique = new ArrayList<>(new LinkedHashSet<>(ids)); // keeps first-seen order
System.out.println(unique);
}
}duplicate: 221
duplicate: 104
[104, 221, 357, 489]A LinkedHashSet removes duplicates and keeps the original order. A plain HashSet would remove them too, but in an unspecified order.
Set operations#
Union, intersection and difference use the bulk methods. They modify the set they are called on, so work on a copy:
import java.util.Set;
import java.util.TreeSet;
public class Main {
public static void main(String[] args) {
Set<String> chess = Set.of("Asha", "John", "Meera", "Ravi");
Set<String> music = Set.of("John", "Kiran", "Meera", "Priya");
Set<String> both = new TreeSet<>(chess);
both.retainAll(music); // intersection
Set<String> either = new TreeSet<>(chess);
either.addAll(music); // union
Set<String> onlyChess = new TreeSet<>(chess);
onlyChess.removeAll(music); // difference
System.out.println(both);
System.out.println(either);
System.out.println(onlyChess);
}
}[John, Meera]
[Asha, John, Kiran, Meera, Priya, Ravi]
[Asha, Ravi]Using TreeSet copies here keeps the printed results in alphabetical order.
TreeSet: always sorted#
A TreeSet keeps its elements sorted, and offers ordered queries:
import java.util.TreeSet;
public class Main {
public static void main(String[] args) {
TreeSet<Integer> slots = new TreeSet<>(java.util.List.of(16, 9, 14, 11)); // free hours
System.out.println(slots);
System.out.println(slots.first() + " " + slots.last());
System.out.println("Next slot at or after 12: " + slots.ceiling(12));
System.out.println("Latest slot before 12: " + slots.lower(12));
System.out.println("Slots before noon: " + slots.headSet(12));
System.out.println(slots.descendingSet());
}
}[9, 11, 14, 16]
9 16
Next slot at or after 12: 14
Latest slot before 12: 11
Slots before noon: [9, 11]
[16, 14, 11, 9]Operations are O(log n). Elements must be comparable (implement Comparable), or you pass a Comparator to the constructor; see Sorting.
Which set?#
Custom objects in sets#
HashSet decides "duplicate or not" with hashCode and equals. For your own classes, override both, or use a record, which generates them:
import java.util.HashSet;
import java.util.Set;
record Point(int x, int y) {}
public class Main {
public static void main(String[] args) {
Set<Point> visited = new HashSet<>();
visited.add(new Point(0, 0));
visited.add(new Point(1, 2));
visited.add(new Point(0, 0)); // equal record: not added again
System.out.println(visited.size() + " " + visited.contains(new Point(1, 2)));
}
}2 trueWith a plain class that does not override equals and hashCode, each new Point(0, 0) would count as a different element.
Common mistakes#
Practice#
Practice exercise
From the text "the quick brown fox jumps over the lazy dog the end", print the distinct words in alphabetical order and how many there are.
Show solution
import java.util.Arrays;
import java.util.Set;
import java.util.TreeSet;
public class DistinctWords {
public static void main(String[] args) {
String text = "the quick brown fox jumps over the lazy dog the end";
Set<String> words = new TreeSet<>(Arrays.asList(text.split(" ")));
System.out.println(words);
System.out.println(words.size() + " distinct words");
}
}[brown, dog, end, fox, jumps, lazy, over, quick, the]
9 distinct wordsKey takeaway#
Finished this lesson?