Гарантирует ли Java Set уникальность элементов? Как это работает?

«Гарантирует ли Java Set уникальность элементов? Как это работает?» — вопрос из категории Java Core, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Да, интерфейс Set в Java гарантирует, что коллекция не содержит дубликатов элементов. Это основное контрактное отличие от List.

Механизм обеспечения уникальности: Реализации Set (такие как HashSet, TreeSet) используют для проверки уникальности комбинацию методов hashCode() и equals().

  1. При добавлении элемента сначала вычисляется его хэш-код (hashCode()).
  2. По хэш-коду определяется «корзина» (bucket), где должен находиться элемент.
  3. Если в этой корзине уже есть элементы, происходит поочередное сравнение нового элемента с существующими через equals(). Если equals() возвращает true для какого-либо элемента, добавление не происходит.

Пример и важное замечание:

Set<String> set = new HashSet<>();
set.add("apple");
set.add("banana");
boolean isAdded = set.add("apple"); // isAdded = false, элемент не добавлен
System.out.println(set); // [apple, banana] (порядок не гарантирован)

Критически важно: Для корректной работы Set с пользовательскими объектами вы должны корректно переопределять equals() и hashCode(), соблюдая их контракт. Иначе уникальность не будет обеспечена.

// ПЛОХО: Класс без переопределенных equals/hashCode
class BadKey {
    String id;
}
Set<BadKey> badSet = new HashSet<>();
badSet.add(new BadKey("a"));
badSet.add(new BadKey("a")); // ДОБАВИТСЯ, т.к. это разные объекты по ==