Class HashSet<E>
This class offers constant time performance for the basic operations ( add , remove , contains and size ), assuming the hash function disperses the elements properly among the buckets. Iterating over this set requires time proportional to the sum of the HashSet instance’s size (the number of elements) plus the «capacity» of the backing HashMap instance (the number of buckets). Thus, it’s very important not to set the initial capacity too high (or the load factor too low) if iteration performance is important.
Note that this implementation is not synchronized. If multiple threads access a hash set concurrently, and at least one of the threads modifies the set, it must be synchronized externally. This is typically accomplished by synchronizing on some object that naturally encapsulates the set. If no such object exists, the set should be «wrapped» using the Collections.synchronizedSet method. This is best done at creation time, to prevent accidental unsynchronized access to the set:
The iterators returned by this class’s iterator method are fail-fast: if the set is modified at any time after the iterator is created, in any way except through the iterator’s own remove method, the Iterator throws a ConcurrentModificationException . Thus, in the face of concurrent modification, the iterator fails quickly and cleanly, rather than risking arbitrary, non-deterministic behavior at an undetermined time in the future.
Note that the fail-fast behavior of an iterator cannot be guaranteed as it is, generally speaking, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification. Fail-fast iterators throw ConcurrentModificationException on a best-effort basis. Therefore, it would be wrong to write a program that depended on this exception for its correctness: the fail-fast behavior of iterators should be used only to detect bugs.
Множества: Set, HashSet, LinkedHashSet, TreeSet
HashSet, TreeSet и LinkedHashSet относятся к семейству Set. В множествах Set каждый элемент хранится только в одном экземпляре, а разные реализации Set используют разный порядок хранения элементов. В HashSet порядок элементов определяется по сложному алгоритму. Если порядок хранения для вас важен, используйте контейнер TreeSet, в котором объекты хранятся отсортированными по возрастанию в порядке сравнения или LinkedHashSet с хранением элементов в порядке добавления.
Множества часто используются для проверки принадлежности, чтобы вы могли легко проверить, принадлежит ли объект заданному множеству, поэтому на практике обычно выбирается реализация HashSet, оптимизированная для быстрого поиска.
В Android 11 (R) обещают добавить несколько перегруженных версий метода of(), которые являются частью Java 8.
HashSet
Название Hash. происходит от понятия хэш-функция. Хэш-функция — это функция, сужающая множество значений объекта до некоторого подмножества целых чисел. Класс Object имеет метод hashCode(), который используется классом HashSet для эффективного размещения объектов, заносимых в коллекцию. В классах объектов, заносимых в HashSet, этот метод должен быть переопределен (override).
Имеет два основных конструктора (аналогично ArrayList):
Методы
- public Iterator iterator()
- public int size()
- public boolean isEmpty()
- public boolean contains(Object o)
- public boolean add(Object o)
- public boolean addAll(Collection c)
- public Object[] toArray()
- public boolean remove(Object o)
- public boolean removeAll(Collection c)
- public boolean retainAll(Collection c) — (retain — сохранить). Выполняет операцию «пересечение множеств».
- public void clear()
- public Object clone()
Методы аналогичны методам ArrayList за исключением того, что метод add(Object o) добавляет объект в множество только в том случае, если его там нет. Возвращаемое методом значение — true, если объект добавлен, и false, если нет.
Перейдём к практике. Как это ни странно, но в жизни встречаются несколько Барсиков, Мурзиков и прочих Рыжиков. Несмотря на одинаковые имена, каждый кот неповторим. Надеюсь, с этим никто не спорит. Но пихать имена котов в множество HashSet не стоит, так как в множестве может храниться только одно имя и двух Мурзиков тут не записать. Другое дело — страны. Не может быть двух Франций, двух Англий, двух Россий (даже партия такая есть Единая Россия, впрочем мы отвлеклись).
Итак, создадим множество стран.
Несмотря на наше упрямство, мы видим только четыре добавленных элемента.
Стоит отметить, что порядок добавления стран во множество будет непредсказуемым. HashSet использует хэширование для ускорения выборки. Если вам нужно, чтобы результат был отсортирован, то пользуйтесь TreeSet.
Преобразовать в массив и вывести в ListView
Следующий пример — задел на будущее. Когда вы узнаете, что такое ListView, то вернитесь к этому уроку и узнайте, как сконвертировать множество в массив и вывести результат в компонент ListView (Список):
Продолжим опыты. Поработаем теперь с числами.
Здесь мы ещё раз убеждаемся, что повторное добавление числа не происходит. В цикле случайным образом выбирается число от 0 до 9 тысячу раз. Естественно, многие числа должны были повториться при таком сценарии, но во множество каждое число попадёт один раз.
При этом данные не сортируются, так как расположены как попало.
Специально для Android был разработан новый класс ArraySet, который более эффективен.
LinkedHashSet
Класс LinkedHashSet расширяет класс HashSet, не добавляя никаких новых методов. Класс поддерживает связный список элементов набора в том порядке, в котором они вставлялись. Это позволяет организовать упорядоченную итерацию вставки в набор.
TreeSet
Переделанный пример для вывода случайных чисел в отсортированном порядке. HashSet не может гарантировать, что данные будут отсортированы, так как работает по другому алгоритму. Если сортировка для вас важна, то используйте TreeSet.
Со строками это выглядит нагляднее:
Названия стран выведутся в алфавитном порядке.
Класс TreeSet создаёт коллекцию, которая для хранения элементов применяет дерево. Объекты сохраняются в отсортированном порядке по возрастанию.
SortedSet
В примере с TreeSet использовался интерфейс SortedSet, который позволяет сортировать элементы множества. По умолчанию сортировка производится привычным способом, но можно изменить это поведение через интерфейс Comparable.
HashSet в Java
Программирование и разработка
В Java встроенный класс с именем HashSet можно использовать для создания коллекции, использующей концепцию хеш-таблицы для хранения элементов. HashMap наследует свойства различных классов и интерфейсов в виде иерархии: HashSet наследует класс «AbstractSet», который реализует интерфейс Set, а интерфейс Set реализует класс Collection, который дополнительно реализует интерфейс Iterable. HashSet существует в пакете java.util.
В этой статье представлен подробный обзор HashSet в java, и в этом отношении он охватывает следующие концепции:
Что такое HashSet
Класс, который хранит только уникальные элементы и не поддерживает какой-либо порядок хранения элементов, называется HashSet в Java.
Как работать с HashSet
Для работы с HashSet необходимо соблюдать приведенные ниже пункты.
Поскольку HashSet принадлежит классу java.util, нам нужно импортировать класс HashSet из пакета java.util :
Следующим шагом является создание объекта, и для этого мы должны следовать следующему синтаксису:
Приведенный выше фрагмент создает объект типа String для HashSet, аналогичным образом мы можем создать объект и других типов данных, для этой цели мы должны указать эквивалентный класс-оболочку для всех этих типов данных, таких как Integer для int, Byte для байт и др.
Как добавить элементы в HashSet
Класс HashSet имеет различные методы для выполнения различных функций, метод add() является одним из них, который можно использовать для добавления элементов в HashSet.
Пример
В приведенном ниже коде мы импортируем класс HashSet вверху нашего проекта, а затем создаем объект класса HashSet. После создания объекта мы использовали этот объект с методом add() для добавления элементов в HashSet:
import java.util.HashSet ;
public class HashSetExamples <
public static void main ( String [ ] args ) <
HashSet animals = new HashSet ( ) ;
animals. add ( «Cat» ) ;
animals. add ( «Dog» ) ;
animals. add ( «Horse» ) ;
animals. add ( «Cat» ) ;
System . out . println ( animals ) ;
>
>
В приведенном выше фрагменте мы создаем объект класса HashSet, а затем добавляем некоторые элементы в HashSet:

Из вывода видно, что HashSet не добавляет повторяющееся значение «cat».
Как проверить наличие элемента в HashSet
Метод contains() можно использовать для проверки существования определенного элемента в HashSet.
Пример
Приведенный ниже фрагмент кода проверяет наличие двух элементов «Собака» и «Лев»:
System . out . println ( animals. contains ( «Dog» ) ) ;
System . out . println ( animals. contains ( «Lion» ) ) ;
Если указанные элементы найдены в HashSet, то метод contains() вернет true:

Вывод подтверждает работу метода contains, поскольку он возвращает true для Dog и false для Lion.
Как удалить элементы из HashSet
Метод remove() можно использовать для удаления элементов из HashSet:
Пример
ниже будет код для удаления «Dog» из HashSet :
Код и соответствующий вывод показаны ниже:

Вывод подтверждает, что метод remove() работает правильно, так как ему удалось удалить указанный элемент.
Как удалить все элементы HashSet
Метод clear() можно использовать для удаления всех элементов из HashSet.
В приведенном ниже фрагменте показано, как работает метод clear():

Пустой HashSet подтверждает работу метода clear().
Как найти размер HashSet
size() можно использовать для определения размера HashSet.
Пример
В приведенном ниже фрагменте кода показано, как найти размер HashSet.
Полный код и его соответствующий вывод показаны на приведенном ниже снимке экрана:

Вывод подтверждает правильность метода size().
Как перебирать HashSet
Мы можем перебирать HashSet, используя итератор, цикл for-each и метод for-each(). Мы можем перебирать элементы и значения HashSet, используя методы keySet() и values() соответственно.
Пример
Мы используем цикл for-each для перебора элементов HashSet:
for ( String i : animals ) <
System . out . println ( i ) ;
>
Полный код и его вывод показаны в приведенном ниже фрагменте:

Вывод показывает, что цикл for-each выполняет итерацию по каждому элементу HashSet.
Заключение
Импорт класса HashSet и последующее создание объекта этого класса позволит использовать все его методы для выполнения различных функций. Класс HashSet предоставляет множество различных методов для достижения различных функций, например, методы add() и remove() могут использоваться для добавления или удаления элементов HashSet соответственно. Точно так же метод contains() можно использовать для проверки существования элемента в HashSet и так далее. В этой статье объясняются различные аспекты класса HashSet. Кроме того, некоторые часто используемые методы используются для выполнения различных функций над HashSet.
Интерфейс Java Set
Интерфейс Java Set, java.util.Set, представляет коллекцию объектов, где каждый объект уникален. Другими словами, один и тот же объект не может встречаться более одного раза в наборе. Интерфейс является стандартным и подтипом интерфейса Collection, что означает, что Set наследуется от Collection.
Вы можете добавить любой объект в набор. Если набор не типизирован с использованием Java Generics, то вы можете даже смешивать объекты разных типов (классов) в одном наборе. Однако в действительности смешивание объектов разных типов в одном наборе не часто выполняется.
Сравнение со списком
Интерфейсы Set и Java List очень похожи друг на друга и представляет собой набор элементов. Тем не менее, есть некоторые существенные различия. Эти различия отражены в методах, которые содержат интерфейсы Set и List.
- Первое различие состоит в том, что один и тот же элемент не может встречаться в наборе более одного раза. Это отличается от списка, где каждый элемент может встречаться более одного раза.
- Второе отличие состоит в том, что элементы в Set не имеют гарантированного внутреннего порядка. Элементы в списке имеют внутренний порядок, и элементы могут быть повторены в этом порядке.
Пример набора
Вот первый простой пример:
В этом примере создается HashSet, который является одним из классов в API Java, которые реализуют интерфейс Set. Затем он добавляет строковый объект в набор и, наконец, проверяет, содержит ли набор только что добавленный элемент.
Установление реализации
Будучи подтипом Collection, все методы в интерфейсе Collection также доступны в интерфейсе Set.
Поскольку Set – это интерфейс, вам нужно создать конкретную реализацию, чтобы использовать его. Вы можете выбрать:
- java.util.EnumSet;
- java.util.HashSet;
- Jawakutilklaidaked ashset;
- java.util.TreeSet.
Каждая из этих реализаций Set ведет себя немного по-разному в отношении порядка элементов при итерации набора и времени (большая запись O), необходимого для вставки и доступа к элементам в наборах.
HashSet поддерживается HashMap. Он не дает никаких гарантий относительно последовательности элементов при их итерации.
LinkedHashSet отличается от HashSet тем, что гарантирует, что порядок элементов во время итерации совпадает с порядком их вставки в LinkedHashSet. Повторная вставка элемента, который уже находится в LinkedHashSet, не меняет этот порядок.
TreeSet также гарантирует порядок элементов при повторении, но он является порядком сортировки элементов. Другими словами, порядок, в котором элементы должны быть отсортированы, если вы использовали Collections.sort() для List или массива, содержащего эти элементы. Этот порядок определяется либо их естественным порядком(если они реализуют Comparable), либо конкретной реализацией Comparator.
Вот несколько примеров того, как создать экземпляр Set:
Добавить элемент в набор
Чтобы добавить элементы в Set, вы вызываете его метод add(). Этот метод унаследован от интерфейса Collection. Вот несколько примеров:
Три вызова add() добавляют экземпляр String к набору.
Перебор элементов набора
Есть два способа перебора элементов набора Java:
- Использование Итератора, полученного из Set.
- Используя цикл for-each.
Обе эти опции описаны в следующих разделах.
При выполнении итерации элементов в Set порядок элементов зависит от того, какую реализацию вы используете.
Итерация множества с помощью итератора
Чтобы выполнить итерацию элементов набора с помощью итератора, сначала необходимо получить его из набора. Вы получаете Iterator из Set, вызывая метод iterator():
Итерация множества с использованием цикла For-Each
Второй способ перебора элементов набора – использование цикла for-each. Вот как выглядит итерация элементов Set с использованием цикла for-each:
Интерфейс Set реализует интерфейс Java Iterable. Вот почему вы можете перебирать элементы набора, используя цикл for-each.
С использованием API Java Stream
Чтобы выполнить итерацию с помощью API-интерфейса Java Stream, необходимо создать поток из набора:
Как удалить элементы
Используется метод remove(Object o):
Невозможно удалить объект на основе индекса в наборе, поскольку порядок элементов зависит от его реализации.
Как удалить все элементы
Используется метод clear():
Как добавить все элементы из другой коллекции
Интерфейс List имеет метод addAll(), который добавляет все элементы из другой Collection (List или Set) в Set. В теории множеств это соответствует объединению множества и другой коллекции . Вот пример:
После выполнения set2 будет содержать четыре элемента String, а также три элемента String: один, два и три из набора.
Как удалить все элементы из другой коллекции
Интерфейс Java Set имеет метод с именем removeAll(), который удаляет все элементы в наборе, также присутствующие в другой коллекции. В теории множеств это называется разницей между множеством и другой коллекцией . Вот пример:
После запуска набор будет содержать элементы String один и два. Третий элемент был удален, потому что он присутствовал в set2, который был задан как параметр для set.removeAll(set2).
Как сохранить все элементы, присутствующие в другой коллекции
Интерфейс Set также имеет метод, который сохраняет все элементы в наборе, также присутствующие в другой коллекции. Все найденные в наборе элементы, которых нет в другой коллекции, будут удалены. В теории множеств это называется пересечением между множеством и другой коллекцией . Вот пример:
После запуска набор будет содержать только элемент String три, так как присутствует как в set, так и в set2.
Как установить размер
Используется метод size(). Размер набора – это количество элементов, содержащихся в наборе. Вот пример чтения размера:
После выполнения переменная размера будет иметь значение 3, потому что созданный в примере набор имеет 3 добавленных элемента.
Как проверить, пуст ли Set
Используется метод isEmpty() для Set:
После запуска этого кода переменная isEmpty будет содержать значение true, потому что Set пуст (в нем нет элементов).
Вы также можете проверить, является ли Set пустым, сравнив значение, возвращаемое методом size() с 0:
После выполнения этого кода переменная isEmpty будет содержать значение true, потому что метод Set size() возвращает 0 – в примере не содержится элементов.
Как проверить, содержится ли элемент
Вы можете проверить, содержит ли Set данный элемент (объект), вызвав метод contains():
После выполнения этого кода переменная contains123 будет содержать значение true, потому что Set на самом деле содержит строку 123.
Чтобы определить, содержит ли набор элемент, он будет внутренне выполнять итерации своих элементов и сравнивать каждый с объектом, переданным в качестве параметра. Для сравнения используется метод равенства.
Поскольку можно добавить нулевые значения, также можно проверить, содержит ли набор нулевое значение:
Очевидно, что если входной параметр для contains() имеет значение null, метод contains() не будет использовать метод equals() для сравнения с каждым элементом, а вместо этого использует оператор ==.
Универсальные
По умолчанию вы можете поместить любой объект в набор, но с Java 5 Java Generics позволяет ограничить типы объектов, которые вы можете вставить:
Этот набор теперь может содержать только экземпляры MyObject. Затем вы можете получить доступ к элементам и выполнить итерацию без их приведения:
Как конвертировать в список
Вы можете преобразовать Set в List, создав List и вызвав его метод addAll(), передав Set в качестве параметра:
После запуска этого примера список будет содержать строковые элементы 123 и 456 – так как это были все элементы, присутствующие в наборе при вызове List addAll(set).