Java HashSet is a hash table data structure implementation of the Set interface based on a HashMap, a part of the Java Collections Framework
HashSet has the following attributes
No guarantees to the iteration order
Provides contains(Object), add(Object) and remove(Object) operations in constant-time performance
Duplicated elements are ignored. A null element is permitted
Compares elements based on theirs equals and hashCode
HashSet is not thread-safe as it is an unsynchronized implementation. In multi-threading environment with at least one thread modifies the set, it must be synchronized externally
Internally, HashSet uses a HashMap instance to store and retrieve its elements
Let's walk through this tutorial to explore them in more details
The class hierarchy
HashSet implements the Set interface which extends from Collection and Iterable interfaces hierarchically
HashSet vs LinkedHashSet and TreeSet
HashSet has no ordering guarantees and runs faster than TreeSet (constant-time vs log-time for most operations)
LinkedHashSet provides insertion-ordered iteration and run nearly as fast as HashSet
TreeSet provides value-ordered iteration. TreeSet can be used to sort a HashSet or LinkedHashSet
Declare a HashSet
As a result from the class hierarchy, you can declare a HashSet with the following ways
@Test
public void declare() {
Set<Integer> set1 = new HashSet<>();
assertThat(set1).isInstanceOf(HashSet.class);
HashSet<Integer> set2 = new HashSet<>();
}
Create and Initialize
Provide either Set.of or List.of factory method, since Java 9, or Arrays.asList factory method to the HashSet(Collection) constructor to create and init a HashSet in one line at the creation time
You can also use add or addAll method to initialize a HashSet after the creation time
@Test
public void initializeWithAdd() {
// Create a new HashSet
Set<Integer> set = new HashSet<>();
// Add elements to HashSet
set.add(3);
set.add(1);
set.add(2);
// Can add null element
set.add(null);
// Duplicate element will be ignored
set.add(2);
assertThat(set).hasSize(4);
// The output ordering will be vary as Set is not reserved the insertion order
System.out.println(set);
}
Iterate
Iterate over a HashSet by using Java 8+ forEach(Consumer)
@Test
public void iterate() {
Set<Integer> set = new HashSet<>(Set.of(3, 1, 2));
set.forEach(ele -> System.out.printf("%d ", ele));
}
Filter and Retrieve
You can filter a HashSet by using Java 8+ Stream APIs
@Test
public void filter() {
Set<Integer> set = new HashSet<>(Set.of(3, 1, 2));
Integer[] arr = set.stream().filter(e -> e >= 2).toArray(Integer[]::new);
assertThat(arr).contains(2, 3);
}
Examine, Add and Remove
- HashSet provides contains(Object), add(Object) and remove(Object) methods in a constant-time performance to examine if a HashSet contains the specified element, to add a new element, and remove an existing element from a HashSet respectively
@Test
public void containsAddRemoveSingleElement() {
Set<Integer> hashSet = new HashSet<>(Set.of(1, 2, 3));
Boolean contained = hashSet.contains(3);
assertThat(contained).isTrue();
hashSet.add(4);
hashSet.add(4);
hashSet.add(null);
assertThat(hashSet).contains(1, 2, 3, 4, null);
hashSet.remove(2);
assertThat(hashSet).contains(1, 3, 4, null);
}
- You can also do the above operations in bulk with containsAll, addAll, removeAll, Java 8+ removeIf
@Test
public void containsAddRemoveMultipleElements() {
Set<Integer> hashSet = new HashSet<>(Set.of(1, 2, 3));
Boolean contained = hashSet.containsAll(Set.of(1, 2));
assertThat(contained).isTrue();
hashSet.addAll(Set.of(3, 4, 5));
assertThat(hashSet).contains(1, 2, 3, 4, 5);
hashSet.removeAll(Set.of(1, 2, 6));
assertThat(hashSet).contains(3, 4, 5);
hashSet.removeIf(e -> e >= 4);
assertThat(hashSet).contains(3);
}
Objects comparing in HashSet
Internally, HashSet basic operations such as contains, add and remove work based on comparing its element objects which depend on their equals and hashCode implementation
In the following example,
hashSet.contains(new Book(1, "a"))
should return true but false,hashSet.add(new Book(1, "a"))
should not but success andhashSet.remove(new Book(1, "a"))
should success but not , due to lack of equals and hashCode implementation on the custom class
@Test
public void objectsComparingProblem(){
Set<Book> hashSet = new HashSet<>();
hashSet.add(new Book(1, "a"));
Boolean contained = hashSet.contains(new Book(1, "a"));
assertThat(contained).isFalse();
hashSet.add(new Book(1, "a"));
assertThat(hashSet).hasSize(2);
hashSet.remove(new Book(1, "a"));
assertThat(hashSet).hasSize(2);
}
static class Book {
int id;
String title;
Book(int id, String title) {
this.id = id;
this.title = title;
}
int getId() {
return id;
}
String getTitle() {
return title;
}
}
- You can fix the above problem by overriding equals and hashCode as the below example
@Test
public void objectsComparingFixed(){
Set<BookFixed> hashSet = new HashSet<>();
hashSet.add(new BookFixed(1, "a"));
Boolean contained = hashSet.contains(new BookFixed(1, "a"));
assertThat(contained).isTrue();
hashSet.add(new BookFixed(1, "a"));
assertThat(hashSet).hasSize(1);
hashSet.remove(new BookFixed(1, "a"));
assertThat(hashSet).hasSize(0);
}
static class BookFixed {
int id;
String title;
BookFixed(int id, String title) {
this.id = id;
this.title = title;
}
int getId() {
return id;
}
String getTitle() {
return title;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
BookFixed bookFixed = (BookFixed) o;
return id == bookFixed.id &&
Objects.equals(title, bookFixed.title);
}
@Override
public int hashCode() {
return Objects.hash(id, title);
}
}
Sort a HashSet
Java doesn't have a direct API to sort a HashSet, you have to convert it to TreeSet or ArrayList
@Test
public void sort() {
Set<Integer> set = new HashSet<>(Set.of(3, 1, 2));
NavigableSet<Integer> sortedSet = new TreeSet<>(set);
// Asserts that the set contains the given values in order
assertThat(sortedSet).containsExactly(1, 2, 3);
}
Conclusion
In this tutorial, we learned about HashSet class hierarchy, features and operations. You can find below the full source code