Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

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
1

To 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: spam

Like 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: red

If the data may repeat, create the set with new HashSet<>(List.of(...)).

Thanks for reading!

Donate to the site — we work hard for you.