Sets: Set
A set (Set) stores only unique elements: adding one again changes nothing. It answers the question "is this element here?" much faster than a list.
HashSet
The main set implementation is HashSet. The add() method returns true if the element was added and false if it was already there:
void main() {
Set<String> tags = new HashSet<>();
IO.println(tags.add("java"));
IO.println(tags.add("java"));
IO.println(tags.size());
}Output:
true
false
1To tell that an element is already there, a set calls hashCode() and equals(). Strings, numbers and records can do this out of the box, but in your own classes these methods must be overridden — otherwise two identical objects end up in the set twice.
Checking presence
A set's contains() method works almost instantly even on a million elements, whereas a list checks elements one by one. That is why a set is chosen when you often need to ask "have we seen this already?":
void main() {
Set<String> banned = Set.of("spam", "ads");
String word = "spam";
if (banned.contains(word)) {
IO.println("Banned word: " + word);
}
}Output:
Banned word: spamLike List.of(), the Set.of() method creates an unmodifiable set.
Element order
HashSet does not keep the insertion order: elements are placed the way that suits fast lookup. If order matters, there are two other implementations. LinkedHashSet remembers the insertion order, and TreeSet keeps elements sorted:
void main() {
Set<String> linked = new LinkedHashSet<>();
Set<String> sorted = new TreeSet<>();
for (String city : List.of("Rome", "Berlin", "Oslo", "Berlin")) {
linked.add(city);
sorted.add(city);
}
IO.println(linked);
IO.println(sorted);
}Output:
[Rome, Berlin, Oslo]
[Berlin, Oslo, Rome]Removing duplicates from a list
A common trick: pass a list to a set's constructor — duplicates disappear by themselves. LinkedHashSet also keeps the original order:
void main() {
List<Integer> visits = List.of(3, 1, 3, 2, 1);
List<Integer> unique = new ArrayList<>(new LinkedHashSet<>(visits));
IO.println(unique);
}Output:
[3, 1, 2]Set operations
The addAll(), retainAll() and removeAll() methods give union, intersection and difference. They change the set they are called on, so you make a copy first:
void main() {
Set<String> anna = Set.of("cinema", "books", "running");
Set<String> oleg = Set.of("running", "chess", "cinema");
Set<String> common = new TreeSet<>(anna);
common.retainAll(oleg);
IO.println("Common: " + common);
Set<String> onlyAnna = new TreeSet<>(anna);
onlyAnna.removeAll(oleg);
IO.println("Only Anna: " + onlyAnna);
}Output:
Common: [cinema, running]
Only Anna: [books]Common mistake
Set.of() does not accept repeated values: instead of silently dropping a duplicate, it throws an exception:
void main() {
Set<String> colors = Set.of("red", "green", "red");
}Output:
Exception in thread "main" java.lang.IllegalArgumentException: duplicate element: redIf the data may repeat, create the set with new HashSet<>(List.of(...)).