Java HashSet – HashSet in Java

Filed Under: Java

Java HashSet is the most popular implementation of Set interface. java.util.HashSet is backed by a HashMap. HashSet extends AbstractSet class and implements Set, Cloneable and Serializable interfaces.

Java HashSet

java hashset, hashset, hashset in java, java hashset example

Some of the important points about HashSet in java are;

  1. HashSet doesn’t allow duplicate entries.
  2. HashSet allows null as a value.
  3. HashSet doesn’t guarantee the insertion order of elements.
  4. HashSet is not thread-safe. You can get thread-safe HashSet using Collections.synchronizedSet method at the cost of performance. You can also use CopyOnWriteArraySet concurrency class for thread safety.
  5. HashSet iterator methods are fail-fast. So any structural modification to the set after creation of iterator will throw ConcurrentModificationException.
  6. HashSet supports Generics, this is the recommended approach to avoid ClassCastException at runtime.
  7. HashSet uses HashMap for storing elements, so the objects should provide good implementation of hashCode() and equals() method to avoid unwanted results.

Java HashSet Constructors

Java HashSet provides four constructors.

  1. public HashSet(): Creates a new empty HashSet, the backing HashMap is initialized with default initial capacity as 16 and load factor 0.75.
  2. public HashSet(int initialCapacity): Creates a empty HashSet with backing HashMap initialized with specified capacity and load factor 0.75.
  3. public HashSet(int initialCapacity, float loadFactor): Creates a empty HashSet with backing HashMap initialized with specified capacity and specified load factor.
  4. public HashSet(Collection<? extends E> c): Creates a new Set containing the elements in the specified collection. The backing HashMap is created with default load factor (0.75) and an initial capacity sufficient enough to contain all the elements in the specified collection.

Below code snippet is showing all these HashSet constructors example usage.


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

//initial capacity should be power of 2
set = new HashSet<>(32); 

//setting backing HashMap initial capacity and load factor
set = new HashSet<>(32, 0.80f);

//creating HashSet from another Collection
Set<String> set1 = new HashSet<>(set);
Set<String> set2 = new HashSet<>(new ArrayList<>());

Java HashSet Methods

Some of the useful HashSet methods are;

  1. public boolean add(E e): Adds the given element to the Set if not already present. This method internally uses equals() method to check for duplicates, so make sure your object defines equals() method properly.
  2. public void clear(): Removes all the elements from the Set.
  3. public Object clone(): Returns a shallow copy of the Set instance.
  4. public boolean contains(Object o): Returns true if the Set contains the given element, othrweise false.
  5. public boolean isEmpty(): Returns true if Set contains no elements, otherwise false.
  6. public Iterator<E> iterator(): Returns an iterator over the elements in this set. The elements are returned in no particular order.
  7. public boolean remove(Object o): Removes the given element from this set if it is present and return true. If the element is not present in the set, just returns false.
  8. public int size(): Returns the number of elements in the set.
  9. public Spliterator<E> spliterator(): Creates a late-binding and fail-fast Spliterator over the elements in this set. This is introduced in Java 8, however I have not used it till now.
  10. public boolean removeAll(Collection<?> c): HashSet inherits this method from AbstractSet. This method will remove all the elements in the set that are part of the specified collection.

Java HashSet Example

Java HashSet example program showing common usage of HashSet in java.


package com.journaldev.examples;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

public class HashSetExample {

	public static void main(String[] args) {

		Set<String> fruits = new HashSet<>();
		
		//add example
		fruits.add("Apple");
		fruits.add("Banana");
		
		//isEmpty example
		System.out.println("fruits set is empty = "+fruits.isEmpty());

		//contains example
		System.out.println("fruits contains Apple = "+fruits.contains("Apple"));
		System.out.println("fruits contains Mango = "+fruits.contains("Mango"));
		
		//remove example
		System.out.println("Apple removed from fruits set = "+fruits.remove("Apple"));
		System.out.println("Mango removed from fruits set = "+fruits.remove("Mango"));
		
		//size example
		System.out.println("fruits set size = "+fruits.size());
		
		//addAll example
		List<String> list = new ArrayList<>(); 
		list.add("Apple"); list.add("Apple"); 
		list.add("Banana"); list.add("Mango");
		
		System.out.println("fruits set before addAll = "+fruits);
		System.out.println("list = "+list);
		fruits.addAll(list);
		System.out.println("fruits set after addAll = "+fruits);

		//iterator example
		Iterator<String> iterator = fruits.iterator();
		while(iterator.hasNext()){
			System.out.println("Consuming fruit "+iterator.next());
		}
		
		//removeAll example
		fruits.add("Orange");
		System.out.println("fruits set before removeAll = "+fruits);
		System.out.println("list = "+list);
		fruits.removeAll(list);
		System.out.println("fruits set after removeAll = "+fruits);
		
		//clear example
		fruits.clear();
		System.out.println("fruits set is empty = "+fruits.isEmpty());

	}

}

Output of above HashSet example program is given below, I am not explaining them since they are self understood.


fruits set is empty = false
fruits contains Apple = true
fruits contains Mango = false
Apple removed from fruits set = true
Mango removed from fruits set = false
fruits set size = 1
fruits set before addAll = [Banana]
list = [Apple, Apple, Banana, Mango]
fruits set after addAll = [Apple, Mango, Banana]
Consuming fruit Apple
Consuming fruit Mango
Consuming fruit Banana
fruits set before removeAll = [Apple, Mango, Orange, Banana]
list = [Apple, Apple, Banana, Mango]
fruits set after removeAll = [Orange]
fruits set is empty = true

Java HashSet ConcurrentModificationException Example

Java HashSet iterator is fail-fast, so it’s methods will throw java.util.ConcurrentModificationException if Set is structurally modified. Below is a simple example demonstrating this.


package com.journaldev.examples;

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

public class HashSetConcurrentModificationExceptionExample {

	public static void main(String[] args) {
		Set<String> fruits = new HashSet<>();
		
		//add example
		fruits.add("Apple");
		fruits.add("Banana");
		fruits.add("Orange");
		fruits.add("Mango");
		
		Iterator<String> iterator = fruits.iterator();
		
		while(iterator.hasNext()){
			String fruit = iterator.next();
			System.out.println("Processing "+fruit);
			
			//wrong way of removing from Set, can throw java.util.ConcurrentModificationException
			if("Orange".equals(fruit)) fruits.remove("Orange");
		}
	}

}

I am getting below output and exception when above program is executed.


Processing Apple
Processing Mango
Processing Orange
Exception in thread "main" java.util.ConcurrentModificationException
	at java.util.HashMap$HashIterator.nextNode(HashMap.java:1429)
	at java.util.HashMap$KeyIterator.next(HashMap.java:1453)
	at com.journaldev.examples.HashSetConcurrentModificationExceptionExample.main(HashSetConcurrentModificationExceptionExample.java:21)

Note that HashSet elements are not guaranteed to be ordered and ConcurrentModificationException is being thrown by iterator.next() call. So if the “Orange” is the last one in the iterator, you will not get the exception because iterator.hasNext() will return false and iterator.next() will not get called.

We should always use Iterator methods for structural modification, as shown in below example code.


package com.journaldev.examples;

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

public class HashSetConcurrentModificationExceptionExample {

	public static void main(String[] args) {
		Set<String> fruits = new HashSet<>();
		
		fruits.add("Apple");
		fruits.add("Banana");
		fruits.add("Orange");
		fruits.add("Mango");
		
		Iterator<String> iterator = fruits.iterator();
		
		while(iterator.hasNext()){
			String fruit = iterator.next();
			System.out.println("Processing "+fruit);
			
			//correct way of structural modification of Set
			if("Orange".equals(fruit)) iterator.remove();
		}
		System.out.println("fruits set after iteration = "+fruits);
	}

}

Above HashSet iterator example will not throw exception and you will get below output.


Processing Apple
Processing Mango
Processing Orange
Processing Banana
fruits set after iteration = [Apple, Mango, Banana]

Java HashSet to Array Example

Sometimes we have to convert HashSet to array and vice versa. Below is a simple program showing correct way to convert HashSet to array and then Array to HashSet.


package com.journaldev.examples;

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

public class HashSetToArrayExample {

	public static void main(String[] args) {
		Set<Integer> ints = new HashSet<>();
		for(int i=0; i<10; i++){
			ints.add(i);
		}
		System.out.println("ints set = "+ints);
		
		// set to array example
		Integer[] intArray = new Integer[ints.size()];
		intArray = ints.toArray(intArray);
		System.out.println("intArray = "+Arrays.toString(intArray));
		ints.remove(0);ints.remove(1);
		System.out.println("intArray = "+Arrays.toString(intArray));
		
		
		//array to set example
		ints = new HashSet<>(Arrays.asList(intArray));
		System.out.println("ints from array = "+ints);
		ints.remove(0);ints.remove(1);
		System.out.println("ints from array after remove = "+ints);
		System.out.println("intArray = "+Arrays.toString(intArray));


	}

}

Output of above HashSet to array example is;


ints set = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
intArray = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
intArray = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
ints from array = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
ints from array after remove = [2, 3, 4, 5, 6, 7, 8, 9]
intArray = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

Java HashSet to List Example

There is not much difference between Set and List, but sometimes we have to convert from Set to List or List to Set. Below is a simple example showing correct way to convert Set to List and then List to Set in java.


package com.journaldev.examples;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class HashSetToListExample {

	public static void main(String[] args) {
		Set<String> vowels = new HashSet<>();
		vowels.add("a"); vowels.add("e"); vowels.add("i");
		
		//set to list example
		List<String> vowelsList = new ArrayList<>(vowels);
		System.out.println("vowels set = "+vowels);
		System.out.println("vowelsList = "+vowelsList);
		
		vowels.add("o");
		vowelsList.add("a");vowelsList.add("u");
		System.out.println("vowels set = "+vowels);
		System.out.println("vowelsList = "+vowelsList);
		
		//list to set example
		vowels = new HashSet<>(vowelsList);
		System.out.println("vowels set = "+vowels);
		
	}

}

Output of above java Set to List example program is;


vowels set = [a, e, i]
vowelsList = [a, e, i]
vowels set = [a, e, i, o]
vowelsList = [a, e, i, a, u]
vowels set = [a, e, u, i]

Java HashSet equals() and hashCode() methods

HashSet utilise HashMap for storing it’s elements. HashSet works with equals() and hashCode() method to check for duplicate element when you try to add an element. Let’s see what happens if you Set object doesn’t provide equals() method implementation.


package com.journaldev.examples;

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

public class HashSetEqualsMethodImportance {

	public static void main(String[] args) {

		Set<Emp> emps = new HashSet<>();
		emps.add(new Emp(1,"Pankaj"));
		emps.add(new Emp(2, "David"));
		emps.add(new Emp(1, "Pankaj"));
		
		System.out.println(emps);
	}

}

class Emp {
	private String name;
	private int id;

	public Emp(int i, String n) {
		this.id = i;
		this.name = n;
	}
	
	@Override
	public String toString(){
		return "{"+id+","+name+"}";
	}
}

When we run above program, we get below output for Set elements.


[{2,David}, {1,Pankaj}, {1,Pankaj}]

So it looks like we were able to store duplicate elements in the Set. Actually not, it’s happening because Emp class doesn’t define equals() method, so Object class equals() method implementation is used. Object class defines equals() method like below.


public boolean equals(Object obj) {
        return (this == obj);
    }

So when adding a new element, object reference is being checked rather than content. Hence we have objects with duplicate content, however they are having different references. Let’s see what happens when we define hashCode() and equals() methods in the Emp class.


package com.journaldev.examples;

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

public class HashSetEqualsMethodImportance {

	public static void main(String[] args) {

		Set<Emp> emps = new HashSet<>();
		emps.add(new Emp(1,"Pankaj"));
		emps.add(new Emp(2, "David"));
		emps.add(new Emp(1, "Pankaj"));
		
		System.out.println(emps);
		
		Emp e = new Emp(3, "Lisa");
		emps.add(e);
		System.out.println(emps);
		
		//set values to make it duplicate
		e.setId(1);
		System.out.println(emps);
		e.setName("Pankaj");
		System.out.println(emps);
	}

}

class Emp {
	private String name;
	private int id;

	public Emp(int i, String n) {
		this.setId(i);
		this.setName(n);
	}
	
	@Override
	public boolean equals(Object obj){
		if(obj == null || !(obj instanceof Emp)) return false;
		Emp e = (Emp) obj;
		if(e.getId() == this.getId() && this.getName().equals(e.getName())) return true;
		return false;
	}
	
	@Override
	public int hashCode(){
		return getId();
	}
	
	@Override
	public String toString(){
		return "{"+getId()+","+getName()+"}";
	}

	public String getName() {
		return name;
	}

	public int getId() {
		return id;
	}

	public void setName(String name) {
		this.name = name;
	}

	public void setId(int id) {
		this.id = id;
	}

}

This time our program produces following output.


[{1,Pankaj}, {2,David}]
[{1,Pankaj}, {2,David}, {3,Lisa}]
[{1,Pankaj}, {2,David}, {1,Lisa}]
[{1,Pankaj}, {2,David}, {1,Pankaj}]

Notice that HashSet was able to check for duplicate when we tried to add an element. But we can change the object values using setter methods and make it duplicate. It worked because there is no operation done on Set. This is why Immutable objects works better with Set and Map.

That’s all for Java HashSet example tutorial, I hope that all the important things are covered for HashSet in Java. If I have missed anything, please let me know through comments and I will try to add that too.

Comments

  1. David says:

    I just noticed that in the code showing the methods available, you use the method addAll (Collection c) but you forgot to mention that method in the list of methods above.
    Great work on this blog.
    Cheers.

  2. BHARGAV KAWALE says:

    if java.util.HashSet is backed by a HashMap so when we add object in hashset how it internal store in map what is key and what is value.

    1. Deepak jha says:

      Key is the value you add in HashSet and the corresponding value is a dummy value added in hashmap class of Java API. Dummy value is the same for the entire map.

Leave a Reply

Your email address will not be published. Required fields are marked *

close
Generic selectors
Exact matches only
Search in title
Search in content
Search in posts
Search in pages