Hashset Java Example
1. Introduction
The HashSet class is a part of the Java Collection API since JDK 1.2. It extends from the AbstractSet class and implements the Set Java interface. It uses HashMap internally.
You can also check the Java Set Example in the following video:
The HashSet
class contains unique elements. It permits the null
element. It does not maintain the insertion order and is not thread-safe. In this example, I will demonstrate the following items:
- How to create a
HashSet
object - How to read, add, remove, and iterate elements in a
HashSet
- Compare
HashSet
toTreeSet
- Compare
HashSet
toLinkedHashSet
2. Technologies Used
The example code in this article was built and run using:
- Java 11
- Maven 3.3.9
- Eclipse Oxygen
- Junit 4.12
3. Maven Project
3.1 Dependencies
I will include Junit
in the pom.xml
.
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>jcg.zheng.demo</groupId> <artifactId>java-hashset-demo</artifactId> <version>0.0.1-SNAPSHOT</version> <build> <sourceDirectory>src</sourceDirectory> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.0</version> <configuration> <release>11</release> </configuration> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> </dependencies> </project>
4. JUnit Test
4.1 How to Construct HashSet
The HashSet
class has four constructors:
HashSet()
– Constructs a new empty set with default initial capacity (16) and load factor (0.75).HashSet(int initialCapacity)
– Constructs a new empty set with the specified initial capacity and default load factor (0.75).HashSet(int initialCapacity, float loadFactor)
– Constructs a new empty set with the specified initial capacity and the specified load factor.HashSet(Collection c)
– Constructs a new set containing the elements in the specified collection.
In this step, I will show how to create a Hashset
object via these four constructors. I emphasize the HashSet(Collection c)
constructor with the following tests:
via_collection_list
() – create aHashSet
via aList
objectvia_collection_set
() – create aHashSet
via aSet
objectvia_stream
() – create aHashSet
viaStream.of
HashSet_ConstructorTest.java
package jcg.zheng.demo; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; import org.junit.Test; public class HashSet_ConstructorTest { @Test public void via_collection_list() { HashSet<String> fromAnotherCollection = new HashSet<>(Arrays.asList("Mary", "Zheng")); assertFalse(fromAnotherCollection.isEmpty()); assertTrue(fromAnotherCollection.contains("Mary")); assertTrue(fromAnotherCollection.contains("Zheng")); } @Test public void via_collection_set() { Set<String> fromCollectionUtils = Collections.singleton("Mary"); assertFalse(fromCollectionUtils.isEmpty()); assertTrue(fromCollectionUtils.contains("Mary")); } @Test public void via_default_constructor() { // Default initial capacity is 16 // Default load factor is 0.75 HashSet<String> createdByDefaultConstructor = new HashSet<>(); assertTrue(createdByDefaultConstructor.isEmpty()); } @Test public void via_initialCapacity_constructor() { // initial capacity is 0 // Default load factor is 0.75 HashSet<String> createdByDefaultConstructor = new HashSet<>(0); assertTrue(createdByDefaultConstructor.isEmpty()); } @Test public void via_initialCapacity_loadfactor_constructor() { // initial capacity is 0 // load factor is 1 HashSet<String> createdByDefaultConstructor = new HashSet<>(0, 1); assertTrue(createdByDefaultConstructor.isEmpty()); } @Test public void via_list() { List<String> listHasDuplicates = Arrays.asList("Mary", "Zheng", "Mary", "Zheng"); assertEquals(4, listHasDuplicates.size()); HashSet<String> fromList = new HashSet<>(listHasDuplicates); assertEquals(2, fromList.size()); } @Test public void via_stream() { HashSet<String> fromStream = Stream.of("Mary", "Zheng").collect(Collectors.toCollection(HashSet::new)); assertFalse(fromStream.isEmpty()); assertTrue(fromStream.contains("Mary")); assertTrue(fromStream.contains("Zheng")); } @Test public void via_via_anonymous_collection() { @SuppressWarnings("serial") HashSet<String> fromAnonymousClass = new HashSet<>() { { add("Mary"); add("Zheng"); } }; assertFalse(fromAnonymousClass.isEmpty()); assertTrue(fromAnonymousClass.contains("Mary")); assertTrue(fromAnonymousClass.contains("Zheng")); } }
Output
Running jcg.zheng.demo.HashSet_ConstructorTest Tests run: 8, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.001 sec
4.2 HashSet Common Methods
There are several common methods in HashSet:
boolean isEmpty()
– Returnstrue
if this set contains no elements.Iterator<E> iterator()
– Returns an iterator over the elements in this set.boolean add(E e)
– Adds the specified element to this set if it is not already present. It has O(1) complexity.boolean remove(Object o)
– Removes the specified element from this set if it is present. It has O(1) complexity.boolean contains(Object o)
– Returns true if this set contains the specified element. It has O(1) complexity.int size()
– Returns the number of elements in this set. It has O(1) complexity.
HashSet
is not thread safe because it throws ConcurrentModificationException
if multiple threads access a HashSet
object concurrently, and at least one of the threads modifies the set. In this step, I will create test methods to demonstrate.
not_thread_safe_cannot_modify_while_iterate()
– Iterate and modify aHashSet
object by calling theremove()
method will throwConcurrentModificationException
use_iterator_remove
– it’s ok to remove the element via iterator.
HashSetTest.java
package jcg.zheng.demo; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import org.junit.Test; public class HashSetTest { private Set<String> testClass = new HashSet<>(); @Test public void can_add_null() { assertTrue(testClass.isEmpty()); testClass.add(null); assertFalse(testClass.isEmpty()); boolean removed = testClass.remove(null); assertTrue(removed); assertTrue(testClass.isEmpty()); } @Test public void can_read_while_iterate() { testClass.add("Mary"); testClass.add("Zheng"); Iterator<String> iterator = testClass.iterator(); while (iterator.hasNext()) { String item = iterator.next(); System.out.println(item); Iterator<String> iterator2 = testClass.iterator(); while (iterator2.hasNext()) { System.out.println("\titerator2 " + iterator2.next()); } } testClass.clear(); assertTrue(testClass.isEmpty()); } @Test public void no_duplicate() { assertTrue(testClass.isEmpty()); boolean added = testClass.add(null); assertTrue(added); assertFalse(testClass.isEmpty()); added = testClass.add("Mary"); assertTrue(added); assertEquals(2, testClass.size()); added = testClass.add(null); assertFalse(added); added = testClass.add("Mary"); assertFalse(added); boolean removed = testClass.remove("Mary"); assertTrue(removed); assertEquals(1, testClass.size()); removed = testClass.remove("Mary"); assertFalse(removed); } @Test(expected = java.util.ConcurrentModificationException.class) public void not_thread_safe_cannot_modify_while_iterate() { testClass.add("Mary"); testClass.add("Zheng"); Iterator<String> iterator = testClass.iterator(); while (iterator.hasNext()) { String item = iterator.next(); if ("Zheng".equalsIgnoreCase(item)) { testClass.remove(item);// will throw exception } } } @Test public void order_is_not_same_as_inserted() { for (int i = 0; i < 19; i++) { testClass.add(String.valueOf(i)); } // [11, 12, 13, 14, 15, 16, 17, 18, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] System.out.println(testClass.toString()); } @Test public void use_iterator_remove() { testClass.add("Mary"); testClass.add("Zheng"); Iterator<String> iterator = testClass.iterator(); while (iterator.hasNext()) { String item = iterator.next(); if ("Zheng".equalsIgnoreCase(item)) { iterator.remove(); } } assertEquals(1, testClass.size()); assertTrue(testClass.contains("Mary")); assertFalse(testClass.contains("Zheng")); } }
Output
Running jcg.zheng.demo.HashSetTest [11, 12, 13, 14, 15, 16, 17, 18, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] Zheng iterator2 Zheng iterator2 Mary Mary iterator2 Zheng iterator2 Mary Tests run: 6, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.195 sec
4.3 Compare to TreeSet
The TreeSet
class extends from AbstractSet
and the elements are ordered based on their natural ordering. TreeSet
has unique element like HashSet
. But TreeSet
cannot have the null
element.
In this step, I will use test methods to compare HashSet
to TreeSet
.
CompareToTreeSetTest.java
package jcg.zheng.demo; import static org.junit.Assert.assertEquals; import java.util.Arrays; import java.util.ConcurrentModificationException; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import java.util.TreeSet; import org.junit.Test; public class CompareToTreeSetTest { private String[] listHasDuplicates = { "Shan", "Mary", "Mary", "Zheng", "Zheng" }; private Set<String> treeSet = new TreeSet<>(); @Test public void HashSet_is_not_sorted_can_have_null() { listHasDuplicates[listHasDuplicates.length - 1] = null; assertEquals(5, listHasDuplicates.length); Set<String> notOrderHashset = new HashSet<>(Arrays.asList(listHasDuplicates)); System.out.println(notOrderHashset); assertEquals(4, notOrderHashset.size()); } @Test(expected=ConcurrentModificationException.class) public void not_thread_safe_because_cannot_modify_while_iterate() { treeSet.add("Mary"); treeSet.add("Zheng"); treeSet.add("Tom"); Iterator<String> iterator = treeSet.iterator(); while (iterator.hasNext()) { iterator.next(); treeSet.add("Test"); } } @Test(expected = NullPointerException.class) public void TreeSet_can_not_have_null() { treeSet.add(null); } @Test public void TreeSet_is_sorted() { assertEquals(5, listHasDuplicates.length); TreeSet<String> orderedTreeSet = new TreeSet<>(Arrays.asList(listHasDuplicates)); System.out.println(orderedTreeSet); assertEquals(3, orderedTreeSet.size()); assertEquals("Mary", orderedTreeSet.first()); assertEquals("Zheng", orderedTreeSet.last()); } }
Output
Running jcg.zheng.demo.CompareToTreeSetTest [Mary, Shan, Zheng] [null, Shan, Zheng, Mary] Tests run: 4, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.117 sec Results : Tests run: 4, Failures: 0, Errors: 0, Skipped: 0
4.4 Compare to LinkedHashSet
The LinkedHashSet
class extends from HashSet
. The only difference between them is that LinkedHashSet
maintains the insertion order. In this step, I will create test methods to compare HashSet
to LinkedHashSet
.
CompareToLinkedHashSetTest.java
package jcg.zheng.demo; import static org.junit.Assert.assertEquals; import java.util.Arrays; import java.util.LinkedHashSet; import org.junit.Test; public class CompareToLinkedHashSetTest { private String[] listHasDuplicates = { "Shan", "Mary", "Mary", "Zheng", "Zheng" }; private LinkedHashSet<String> setObj; @Test public void is_not_sorted_can_have_null() { assertEquals(5, listHasDuplicates.length); listHasDuplicates[listHasDuplicates.length - 1] = null; assertEquals(5, listHasDuplicates.length); setObj = new LinkedHashSet<>(Arrays.asList(listHasDuplicates)); System.out.println(setObj); assertEquals(4, setObj.size()); } @Test public void LinkedHasSet_keeps_insertion_order() { assertEquals(5, listHasDuplicates.length); setObj = new LinkedHashSet<>(Arrays.asList(listHasDuplicates)); assertEquals(3, setObj.size()); //always "Shan", "Mary", "Zheng" order System.out.println(setObj); } }
Output
Running jcg.zheng.demo.CompareToLinkedHashSetTest [Shan, Mary, Zheng] [Shan, Mary, Zheng, null] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.135 sec
5. Summary
In this example, I demonstrated several ways to create a HashSet
object and how to use its common methods. I also compared HashSet
to TreeSet
and LinkedHashSet
.
HashSet | LinkedHashSet | TreeSet | |
---|---|---|---|
Unique Elements | Yes | Yes | Yes |
Permit Null Element | Yes | Yes | No |
Maintain Insertion Order | No | Yes | No |
Is Sorted | No | No | Yes |
Is thread-safe | No | No | No |
6. More articles
7. Download the Source Code
This example consists of a Maven project which contains several Junit tests to demonstrate the usage of the HashSet
Class.
You can download the full source code of this example here: Hashset Java Example
Last updated on Apr. 23rd, 2021