Interface Set<E>
The Set interface places additional stipulations, beyond those inherited from the Collection interface, on the contracts of all constructors and on the contracts of the add , equals and hashCode methods. Declarations for other inherited methods are also included here for convenience. (The specifications accompanying these declarations have been tailored to the Set interface, but they do not contain any additional stipulations.)
The additional stipulation on constructors is, not surprisingly, that all constructors must create a set that contains no duplicate elements (as defined above).
Note: Great care must be exercised if mutable objects are used as set elements. The behavior of a set is not specified if the value of an object is changed in a manner that affects equals comparisons while the object is an element in the set. A special case of this prohibition is that it is not permissible for a set to contain itself as an element.
Some set implementations have restrictions on the elements that they may contain. For example, some implementations prohibit null elements, and some have restrictions on the types of their elements. Attempting to add an ineligible element throws an unchecked exception, typically NullPointerException or ClassCastException . Attempting to query the presence of an ineligible element may throw an exception, or it may simply return false; some implementations will exhibit the former behavior and some will exhibit the latter. More generally, attempting an operation on an ineligible element whose completion would not result in the insertion of an ineligible element into the set may throw an exception or it may succeed, at the option of the implementation. Such exceptions are marked as «optional» in the specification for this interface.
Getting an element from a Set
Why doesn’t Set provide an operation to get an element that equals another element?
I can ask whether the Set contains an element equal to bar , so why can’t I get that element? 🙁
To clarify, the equals method is overridden, but it only checks one of the fields, not all. So two Foo objects that are considered equal can actually have different values, that’s why I can’t just use foo .
22 Answers 22
To answer the precise question «Why doesn’t Set provide an operation to get an element that equals another element?», the answer would be: because the designers of the collection framework were not very forward looking. They didn’t anticipate your very legitimate use case, naively tried to «model the mathematical set abstraction» (from the javadoc) and simply forgot to add the useful get() method.
Now to the implied question «how do you get the element then»: I think the best solution is to use a Map<E,E> instead of a Set<E> , to map the elements to themselves. In that way, you can efficiently retrieve an element from the «set», because the get() method of the Map will find the element using an efficient hash table or tree algorithm. If you wanted, you could write your own implementation of Set that offers the additional get() method, encapsulating the Map .
The following answers are in my opinion bad or wrong:
«You don’t need to get the element, because you already have an equal object»: the assertion is wrong, as you already showed in the question. Two objects that are equal still can have different state that is not relevant to the object equality. The goal is to get access to this state of the element contained in the Set , not the state of the object used as a «query».
«You have no other option but to use the iterator»: that is a linear search over a collection which is totally inefficient for large sets (ironically, internally the Set is organized as hash map or tree that could be queried efficiently). Don’t do it! I have seen severe performance problems in real-life systems by using that approach. In my opinion what is terrible about the missing get() method is not so much that it is a bit cumbersome to work around it, but that most programmers will use the linear search approach without thinking of the implications.
Интерфейс 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).
Java — how to get element from HashSet?
Tehya-Blanchard
1. Overview
In java Set / HashSet / LinkedHashSet don't have get method.
Ofcourse it is possible to 'GET' element from Set in java, we just need to think a bit different when using this data structure. What I mean by this?
When we want to GET element from Set in java we just need to check if Set contains the object we want to get. So we already have our element we want to get from HashSet, the only think left to do is to check if Set have this object inside by using contains method with correctly implemented hashCode() and equals() .
HashSet internally uses HashMap and contains method on HashSet calls HashMap containsKey method.
Internally HashSet uses HashMap which looks like this:
We can go inside JDK and check it by ourselves.
The best way to understand what I mean is by analyzing below 2 examples.
When we use intellij IDEA we can just click on contains method and attach the debugger inside.
2. Example 1 — HashSet with String
This example uses String, String have internal hashCode and equals implemented in JDK.
String — Internal hashCode and equals implemented in JDK.
HashSet — contains JDK implementation (as we can see HashSet internally uses HashMap)
3. Example 2 — HashSet with custom User objects
In this example we implement explicit hashCode and equals for User class.