August 30, 2022

Java HashSet With Examples

HashSet in Java is part of the Java Collections framework and one of the most used Set implementation in Java applications. HashSet class extends AbstractSet class and implements Set, Cloneable and Serializable interfaces. HashSet is backed by a HashMap instance that means HashSet class internally uses HashMap to store its elements.

Features of HashSet in Java

Some of the features of the HashSet which are discussed in this post are as follows-

  1. HashSet stores only unique elements.
  2. HashSet is an unordered collection, which means insertion order is not maintained as in ArrayList.
  3. HashSet in Java allows null.
  4. HashSet is not thread-safe.
  5. The iterators returned by HashSet's iterator method are fail-fast. Which means, 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.

Java HashSet constructors

HashSet class in Java has 4 constructors.

  • HashSet()- This constructor constructs a new, empty set; the backing HashMap instance has default initial capacity (16) and load factor (0.75).
  • HashSet(int initialCapacity)- This constructor constructs a new, empty set; the backing HashMap instance has the specified initial capacity and default load factor (0.75).
  • HashSet(int initialCapacity, float loadFactor)- This constructor constructs a new, empty set; the backing HashMap instance has the specified initial capacity and the specified load factor.
  • HashSet(Collection<? extends E> c)- This constructor constructs a new set containing the elements in the specified collection.

Capacity and Load Factor for HashSet

As already stated HashSet class in Java internally uses HashMap to store its elements. HashMap in turns uses an array of type Node to store elements. If you don’t specify any capacity while creating HashSet then the array will have default initial capacity of 16.

In HashMap concept of bucket is used so each index of array is conceptualized as one bucket. So, total there are 16 buckets. For every value that is added to HashSet a hash is calculated, based on that hash value one of these buckets is chosen to store the element. That way HashSet is able to offer constant time performance for basic operations like add, remove, contains and size.

Load factor provides the threshold for the HashSet storage. Once the threshold is reached the capacity is doubled. Default load factor is 0.75 which means if the 75% of the capacity is used the HashSet is resized.

To know more about HashSet internal implementation in Java refer this post- HashSet Internal Implementation in Java

Java example creating a HashSet

Let’s see a basic example where a HashSet is created and elements added to it. Then the added elements are displayed.

import java.util.HashSet;
import java.util.Set;

public class HashSetDemo {
  public static void main(String[] args) {
    Set<String> capitalSet = new HashSet<String>();
    // adding elements
    capitalSet.add("New Delhi");
    capitalSet.add("Lisbon");
    capitalSet.add("Buenos Aires");
    capitalSet.add("Beijing");
    // Displaying set elements
    for(String capital : capitalSet){
      System.out.println("Capital city- " + capital);
    }
  }
}
Output
Capital city- Beijing
Capital city- New Delhi
Capital city- Lisbon
Capital city- Buenos Aires

As you can see HashSet of default capacity is created using this statement.

Set<String> capitalSet = new HashSet<String>();

All Collections classes are generic now, so you can specify in the beginning itself what type of elements will be stored in the Set. The Set used in this example can store only Strings.

From the output you can see that the insertion order is not maintained in the HashSet.

Methods in the HashSet class

Here is a list of some of the methods in the HashSet class in Java.

  • add(E e)- Adds the specified element to this set if it is not already present.
  • clear()- Removes all of the elements from this set.
  • clone()- Returns a shallow copy of this HashSet instance: the elements themselves are not cloned.
  • contains(Object o)- Returns true if this set contains the specified element.
  • isEmpty()- Returns true if this set contains no elements.
  • iterator()- Returns an iterator over the elements in this set.
  • remove(Object o)- Removes the specified element from this set if it is present.
  • size()- Returns the number of elements in this set.
  • spliterator()- Creates a late-binding and fail-fast Spliterator over the elements in this set.

Duplicates are not allowed in HashSet

public class HashSetDemo {
  public static void main(String[] args) {
    Set<String> capitalSet = new HashSet<String>();
    // adding elements
    capitalSet.add("New Delhi");
    capitalSet.add("Lisbon");
    capitalSet.add("Buenos Aires");
    capitalSet.add("Beijing");
    // added again
    capitalSet.add("New Delhi");
    System.out.println("HashSet size-- " + capitalSet.size());
    // Displaying set elements
    for(String capital : capitalSet){
      System.out.println("Capital city- " + capital);
    }
  }
}
Output
HashSet size-- 4
Capital city- Beijing
Capital city- New Delhi
Capital city- Lisbon
Capital city- Buenos Aires

As you can see, even if “New Delhi” is added twice it is inserted only once. Size of the HashSet is also 4.

Inserting Null is allowed in HashSet

You can insert null in HashSet but it can be added only once. In the below example null is added twice, in the output you can see that it is inserted only once.

public class HashSetDemo {
  public static void main(String[] args) {
    Set<String> capitalSet = new HashSet<String>();
    // adding elements
    capitalSet.add(null);
    capitalSet.add("New Delhi");
    capitalSet.add("Lisbon");
    capitalSet.add("Buenos Aires");
    capitalSet.add("Beijing");
    capitalSet.add(null);
    System.out.println("HashSet size-- " + capitalSet.size());
    // Displaying set elements
    for(String capital : capitalSet){
      System.out.println("Capital city- " + capital);
    }
  }
}
Output
HashSet size-- 5
Capital city- null
Capital city- Beijing
Capital city- New Delhi
Capital city- Lisbon
Capital city- Buenos Aires

Example code to remove elements from HashSet

public class HashSetDemo {
  public static void main(String[] args) {
    Set<String> capitalSet = new HashSet<String>();
    // adding elements
    capitalSet.add("New Delhi");
    capitalSet.add("Lisbon");
    capitalSet.add("Buenos Aires");
    capitalSet.add("Beijing");
    
    capitalSet.remove("Buenos Aires");
      
    // Displaying set elements
    for(String capital : capitalSet){
      System.out.println("Capital city- " + capital);
    }
    // Removing all elements
    capitalSet.clear();      
    System.out.println("HashSet size after clearing -- " + capitalSet.size());
  }
}
Output
Capital city- Beijing
Capital city- New Delhi
Capital city- Lisbon
HashSet size after clearing – 0

Java HashSet iterator example

You can use an iterator to iterate a HashSet. You can get an Iterator using iterator() method of the HashSet class. The iterators returned by HashSet’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.

Refer How to Iterate a Java HashSet to see different ways to traverse a HashSet in Java.

Let’s try to clarify it with an example. In the code while iterating the HashSet using iterator we’ll try to remove an element using the HashSet’s remove() method not the iterator’s remove method.

public class HashSetDemo {
  public static void main(String[] args) {
    Set<String> capitalSet = new HashSet<String>();
    // adding elements
    capitalSet.add("New Delhi");
    capitalSet.add("Lisbon");
    capitalSet.add("Buenos Aires");
    capitalSet.add("Beijing");
    
    Iterator<String> itr = capitalSet.iterator();
    while(itr.hasNext()){
      String capital = itr.next();
      System.out.println("Capital city- " + capital);
      if(capital.equals("Lisbon")){
        capitalSet.remove(capital);
      }
    }
  }
}

As you can see ConcurrentModificationException exception is thrown as you are trying to structurally modify the HashSet while it is iterated using an iterator.

Output
Capital city- Beijing
Capital city- New Delhi
Capital city- Lisbon
Exception in thread "main" java.util.ConcurrentModificationException
	at java.util.HashMap$HashIterator.nextNode(Unknown Source)
	at java.util.HashMap$KeyIterator.next(Unknown Source)
	at com.knpcode.HashSetDemo.main(HashSetDemo.java:19)
Using iterator’s remove method
public class HashSetDemo {
  public static void main(String[] args) {
    Set capitalSet = new HashSet();
    // adding elements
    capitalSet.add("New Delhi");
    capitalSet.add("Lisbon");
    capitalSet.add("Buenos Aires");
    capitalSet.add("Beijing");
		
    Iterator itr = capitalSet.iterator();
    while(itr.hasNext()){
      String capital = itr.next();
      System.out.println("Capital city- " + capital);
      if(capital.equals("Lisbon")){
        itr.remove();
      }
    }
    System.out.println("** After element removal **");
    // Displaying set elements
    for(String capital : capitalSet){
      System.out.println("Capital city- " + capital);
    }
  }
}
Output
Capital city- Beijing
Capital city- New Delhi
Capital city- Lisbon
Capital city- Buenos Aires
** After element removal **
Capital city- Beijing
Capital city- New Delhi
Capital city- Buenos Aires

As you can see using iterator’s remove method you can remove an element while the HashSet is iterated.

HashSet is not threadsafe

HashSet in Java is not threadsafe. If you are using HashSet in multi-threaded environment where instance of HashSet is shared among many threads, you should synchronize it externally. In order to synchronize Set you can use Collections.synchronizedSet() method which returns a synchronized set backed by the passed set to this method.

As example-
Set tempSet = Collections.synchronizedSet(capitalSet); 

See an example of synchronizing HashSet in Java here- How to Synchronize HashSet in Java

That's all for the topic Java HashSet With Examples. If something is missing or you have something to share about the topic please write a comment.


You may also like

No comments:

Post a Comment