HashSet
Set на основе хеширования
HashSet<E> — распространённая реализация Set.
Она использует хеширование, чтобы быстро определять, хранится ли элемент в наборе.
В стандартной реализации HashSet внутри используется HashMap,
но пользователю множества важнее правило: есть только элементы, без отдельных значений по ключу.
Set<String> emails = new HashSet<>();
emails.add("a@example.com");
emails.add("b@example.com");
emails.add("a@example.com");
System.out.println(emails.size()); // 2
В среднем add(), contains() и
remove() работают за время, близкое к постоянному.
Поэтому HashSet особенно удобен для частых проверок «уже встречалось или нет».
Откуда берётся уникальность
Когда добавляется объект, HashSet использует его
hashCode() и equals().
Если набор находит равный объект, новый экземпляр не добавляется.
Set<String> codes = new HashSet<>();
codes.add(new String("JAVA"));
codes.add(new String("JAVA"));
System.out.println(codes.size()); // 1
Это хороший пример того, что уникальность не связана с тем, один и тот же это объект по ссылке или нет. Важно именно логическое равенство, определённое классом.
Те же риски изменяемых объектов
Если изменить объект так, что изменится его хеш или равенство, пока он находится в HashSet,
проверка contains() может перестать находить этот объект корректно.
Поэтому элементы множества, как и ключи HashMap, должны быть стабильны с точки зрения равенства.