Tech Master Tutorials
Email Facebook Google LinkedIn Pinterest Twitter
Home Java Java 8 Java Interview Questions Java Programming

Set interface

All classes which are child of Set interface can manage single set of elements but no duplicate values allowed. Set is like a mathematical set that can not have duplicate elements. Set is a Collection and hence inherits the methods from the Collection interface and put a restriction on the duplicity of the elements. Objects being added to a set must overwrite the hashcode method if they are overwriting the equals methods as it is necessary to make work the no-duplicacy nature of the objects being added to any Set implimentation.

Java provides the following three Set implementations i.e HashSet, TreeSet, and LinkedHashSet.
  • HashSet : Internally uses a hash table to store the elements. It does not make any guarantee of the ordering of the elements as traversal can give you a different order than the oreder of insertion but provides the best performance in all the implementations of set. So when the ordering of the elements does not matter, it is the best set implementation for use.
  • TreeSet: Intyernally uses a red-black tree to store the elements. TreeSet orders its elements on the baisis of a natural sorting order or any sorting order passed to Comparable.
  • LinkedHashSet: Internally uses a hash table with a linked list implementation. Maintains the order of the elements on the baisis of the insertion order. Lateral traversal will give you the order as the order of insertion. So if you need to maintain the order of insertion then it saves you from the unexpected ordering of the HashSet.


Set Interface Basic Operations

  • size()- returns the cardinality(number of elements in the Set) .
  • isEmpty()- returns¬¬ true if it is empty.
  • add() - adds the specified element if it is not present in the set.
  • remove()- removes the passed element from the Set.
  • Iterator() - returns an Iterator for the Set.

Following program creates a set of Strings using HashSet implementation class and perform basic operations add(), remove(), isEmpty(), size() and iterates over it using an iterator. ---

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

public class SetTest {

	public static void main(String[] args) {
		
		Set<String> strSet=new HashSet<String>();
		
		System.out.println("As of now Set is empty so result for isEmpty() is : "+strSet.isEmpty());
		System.out.println("Size of the Set is Zero so result for size() is : "+strSet.size());
		
		strSet.add("Ram");
		strSet.add("Ajit");
		strSet.add("Bhanu");
		strSet.add("Ram");//Trying to add duplicate element
		
		System.out.println();
		System.out.println("Added elements");
		System.out.println();
		
		System.out.println("After adding elements, result for isEmpty() is : "+strSet.isEmpty());
		System.out.println("After adding elements, result for size() is : "+strSet.size());

		System.out.println("Tried to add 4 elements but size is 3 because we tried to add a duplicate element");
		
		
		System.out.println();
		System.out.println("Printing elements :");
		
		Iterator<String> itr = strSet.iterator();
		//Printing all the Set elements
		while (itr.hasNext()) {
			String string = (String) itr.next();
			System.out.println(string);
			if (string.equals("Ajit")) {
				itr.remove();//Removing "Ajit" from the Set
			}
		}

		System.out.println();
		System.out.println("Printing the below strings from Set after removal of \"Ajit\" :");
		//After removal of the string printing the set strings using for-each construct
		for (String string : strSet) {
			System.out.println(string);
		}
	}
	
}

Traversing Through a Set :

We can traverse a Set using following three ways -

  • Iterators.
  • for-each construct
  • Aggregate Operations
for-each Construct

For-each allows to traverse a Set using a loop. Using for-each we can go through each element and perform some operation like printing the value for the element as shown in the below code snippet. In the below code, a Set to hold string has been prepared which uses a HashSet implementation Using for-each construct traversing and printing the Set values.

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

public class TraversalTestForEach {
	
	public static void main(String[] args) {
		Set<String> strSet=new HashSet<String>();
		
		strSet.add("Ram");
		strSet.add("Ajit");
		strSet.add("Bhanu");
		strSet.add("Ram");
		
		for (String string : strSet) {
			System.out.println(string);
		}
			
	}
		
}
Iterators

An Iterator object enables us to traverse through a Set. Using iterator we can also remove the elements from the Set. Using iterator() method from collection we can get the iterator for the Set and we can traverse through the Set. Iterator interface.

public interface Iterator {
    boolean hasNext();
    E next();
    void remove(); //optional
}

Interator interface has got the following methods:

  1. boolean hasNext() – returns true if iterator has more elements to be traversed
  2. next() – returns the next element in the iteration
  3. remove() – removes the last element from the Set that was returned by the next. It can be called ony once after the next() has been called otherwise throws exception. Interator is the only safe way to modify the Set during iteration. In any other case unexpected events can happen.

Following is the code snippet to traverse Set using iterator.

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

public class TraversalTestIterator {
	public static void main(String[] args) {
		Set<String> strSet = new HashSet<String>();

		strSet.add("Ram");
		strSet.add("Ajit");
		strSet.add("Bhanu");
		strSet.add("Ram");

		Iterator<String> itr = strSet.iterator();

		while (itr.hasNext()) {
			String string = (String) itr.next();
			System.out.println(string);
		}
	}
}
Aggregate Operations

JDK 8 release has introduced a new method which is also preferred method to traverse that is to obtain a stream over the collection(Set) and perform aggregate operations on it. Some of the aggregate operations are provided with the capability to use lambda expressions with them. Lambda expressions provides the capability to pass the code as parameters in the form of functional interfaces. Lambda expressions make the code short(lesser lines of code) and expressive.
The following code iterates through the Set and prints the values:

import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;

public class TraversalUsingAggregateFun {

	public static void main(String[] args) {

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

		strSet.add("Ram");
		strSet.add("Ajit");
		strSet.add("Bhanu");
		strSet.add("Ram");

		/*
		 * JDK 8 release has introduced a new method which is also preferred
		 * method to traverse that is to obtain a stream over the collection and
		 * perform aggregate operations on it. Aggregate operations are provided
		 * with the capability to use lambda expressions with them. Lambda
		 * expressions provides the capability to pass the code as param,eters
		 * in the form of functional interfaces. Lambda expressions make the
		 * code short(lesser lines of code) and expressive. The following code
		 * iterates through the collection and prints the values:
		 */

		/*
		 * In the below code, first we are getting the stream on the collection
		 * and traversing using the forEach() function and within the function
		 * paasing a Lambda Expression to print each element.
		 */

		System.out.println("Printing using stream along with a filter operation :");
		strSet.stream()
		.filter(e -> e.length() == 4)
		.forEach(e -> System.out.println(e));

		System.out.println();
		System.out.println("Printing all the elements using stream :");
		strSet.stream()
		.forEach(s -> System.out.println(s));

		/*
		 * Stream API also provides a parallel stream which will work
		 * efficiently with a large collection if computer system got multiple
		 * cores.
		 */

		System.out.println();
		System.out.println("Printing using parallel stream along with a filter operation :");
		strSet.parallelStream()
		.filter(e -> e.length() == 4)
		.forEach(e -> System.out.println(e));

		System.out.println();
		System.out.println("Printing all the elements using parallel stream :");
		strSet.parallelStream()
		.forEach(e -> System.out.println(e));

		/*
		 * There are other methods provided as part of the stream API using
		 * which we can collect data and perform operations. For example, having
		 * a collection of string and want to join them using comma as shown in
		 * the below code
		 */

		System.out.println();
		System.out.println("Performing an aggregate operation over stream : ");
		String joined = strSet.stream()
				.collect(Collectors.joining(", "));
		System.out.println("Joined String --> " + joined);

	}

}