Core Java

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.

Hashset Java
Figure 1 HashSet

You can also check the Java Set Example in the following video:

Java Set Example – 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 to TreeSet
  • Compare HashSet to LinkedHashSet

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 a HashSet via a List object
  • via_collection_set() – create a HashSet via a Set object
  • via_stream() – create a HashSet via Stream.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() – Returns true 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 a HashSet object by calling the remove() method will throw ConcurrentModificationException
  • 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.

HashSetLinkedHashSetTreeSet
Unique ElementsYesYesYes
Permit Null ElementYesYesNo
Maintain Insertion OrderNoYesNo
Is SortedNoNoYes
Is thread-safeNoNoNo

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.

Download
You can download the full source code of this example here: Hashset Java Example

Last updated on Apr. 23rd, 2021

Mary Zheng

Mary has graduated from Mechanical Engineering department at ShangHai JiaoTong University. She also holds a Master degree in Computer Science from Webster University. During her studies she has been involved with a large number of projects ranging from programming and software engineering. She works as a senior Software Engineer in the telecommunications sector where she acts as a leader and works with others to design, implement, and monitor the software solution.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button