HashSet vs LinkedHashSet vs TreeSet In Java

All HashSet, LinkedHashSet, and TreeSet In Java have some similarities, Like:

  • Can not contain duplicate items: All HashSet, LinkedHashSet, and TreeSet are implements Set interface. So they are not allowed to contains duplicates elements or objects.
  • Not Thread Safe: All three are not synchronized and hence not Thread safe.
  • Cloneable and Serializable: All three (HashSet, LinkedHashSet, TreeSet) are Cloneable and Serializable.
  • fail-fast Iterator: All three will returne fail-fast Iterator. That is, ConcurrentModificationException will be thrown, if you try to modify the Iterator object after creation.

Set Hierarchy:

HashSet:

HashSet represents a group of unique elements and it does not maintains any order for it’s objects or elements. It extends AbstractSet and implements the Set interface. HashSet uses hash table for it’s internal storage.

Example

import java.util.*;  
public class Main {  
 
    public static void main(String args[]){  
          // Create HashSet
          HashSet subjects = new HashSet<>();
 
          // Add elements to HashSet
          subjects.add("Java");
          subjects.add("Angular");
          subjects.add("Spring");
          subjects.add("Oracle");
          subjects.add("MySQL");
 
          //Add duplicate elements to HashSet
          subjects.add("Java");
          subjects.add("Spring");
 
          //Add null values to HashSet
          subjects.add(null);
          subjects.add(null);
 
          //Print HashSet elements
          System.out.println(subjects);
 
    }  
}

Output

[null, Java, MySQL, Spring, Oracle, Angular]

LinkedHashSet:

LinkedHashSet extends HashSet class and implements Set interface. Like HashSet, it also represents a group of unique objects but it maintains insertion order for them.

Example

import java.util.*;  
public class Main {  
 
    public static void main(String args[]){  
          // Create LinkedHashSet
          LinkedHashSet subjects = new LinkedHashSet<>();
 
          // Add elements to HashSet
          subjects.add("Java");
          subjects.add("Angular");
          subjects.add("Spring");
          subjects.add("Oracle");
          subjects.add("MySQL");
 
          //Add duplicate elements to LinkedHashSet
          subjects.add("Java");
          subjects.add("Spring");
 
          //Add null values to LinkedHashSet
          subjects.add(null);
          subjects.add(null);
 
          //Print LinkedHashSet elements
          System.out.println(subjects);
 
    }  
}

Output

[Java, Angular, Spring, Oracle, MySQL, null]

TreeSet:

TreeSet extends AbstractSet and implements NavigableSet interface. Like HashSet and LinkedHashSet it also represents a group of unique elements but maintains ascending order for them.

Example

import java.util.*;  
public class Main {  
 
    public static void main(String args[]){  
          // Create TreeSet
          TreeSet subjects = new TreeSet<>();
 
          // Add elements to HashSet
          subjects.add("Java");
          subjects.add("Angular");
          subjects.add("Spring");
          subjects.add("Oracle");
          subjects.add("MySQL");
 
          //Add duplicate elements to TreeSet
          subjects.add("Java");
          subjects.add("Spring");
 
          //Print TreeSet elements
          System.out.println(subjects);
 
    }  
}

Output

[Angular, Java, MySQL, Oracle, Spring]

When to use HashSet, LinkedHashSet, and TreeSet:

  • Use HashSet: When there is no need to keep any order in elements but group of unique objects is needed.
  • Use LinkedHashSet: When group of unique elements is needed and insertion order of elements is also required.
  • Use TreeSet: When group of unique items/elements/objects is needed and sorting of the elements is required according to some Comparator.

Difference between HashSet, LinkedHashSet, and TreeSet

HashSet LinkedHashSet TreeSet
HashSet uses HashMap as its internal data structure to store objects. LinkedHashSet uses LinkedHashMap as its internal data structure to store objects. TreeSet uses TreeMap as its internal data structure to store objects.
We should use HashSet, when no insertion order or sorting of elements is required but wants to store unique objects. We should use LinkedHashSet, when insertion order of elements is required. We should use TreeSet, when sorting order of elements is required based on some Comparator.
It does not maintain any order of objects. It maintains insertion order of objects By-Default, it maintains ascending order of objects. We can provide custom sorting algorithm by using Comparator.
It has O(1) order of complexity for insertion, removing, and accessing objects It has O(1) order of complexity for insertion, removing, and accessing objects It has O(log(n)) order of complexity for insertion, removing, and accessing objects
HashSet performance is best among all three. LinkedHashSet performance is slow as compared to TreeSet except insertion and removal operations. LinkedHashSet performance is almost similar to HashSet but slightly slower because, it uses LinkedList internally to maintain the insertion order of it’s elements. TreeSet performance is better as compared to LinkedHashSet except insertion and removal operations because, it has to sort it’s elements after every insertion and removal operations.
It uses equals() and hashCode() methods to compare it’s elements. It uses equals() and hashCode() methods to compare it’s elements/objects. It uses compare() and compareTo() methods to compare it’s elements or objects.
It allows only one null object. Like HashSet, it also allows only one null object. It does not allow any null objects. If you try to add null objects into TreeSet, it will throw NullPointerException
Syntax:

HashSet hashSet = new HashSet();

Syntax:

LinkedHashSet linkedHashSet = new LinkedHashSet();

Syntax:

TreeSet treeSet = new TreeSet();

Performance difference between HashSet, LinkedHashSet, and TreeSet

import java.util.*;  
public class Main {  
 
    //Method to display order of objects in HashSet 
    private static void objectsOrderHashSet() 
    { 
        HashSet<String> hashSet = new HashSet<String>(); 
 
        // Add object in HashSet 
        for (String str : Arrays.asList("Java", "Spring", "Hibernate")) {
            hashSet.add(str); 
        } 
 
        System.out.println("Order of objects in HashSet :" + hashSet); 
    } 
 
    //Method to display order of objects in LinkedHashSet 
    private static void objectsOrderLinkedHashSet() 
    { 
        LinkedHashSet<String> linkedHashSet = new LinkedHashSet<String>(); 
 
        // Add object in LinkedHashSet 
        for (String str : Arrays.asList("Java", "Spring", "Hibernate")) {
            linkedHashSet.add(str); 
        } 
 
        System.out.println("Order of objects in LinkedHashSet :" + linkedHashSet);
    } 
 
    //Method to display order of objects in TreeSet
    private static void objectsOrderTreeSet() 
    { 
        TreeSet<String> treeSet = new TreeSet<String>(); 
 
        // Add object in TreeSet 
        for (String str : Arrays.asList("Java", "Spring", "Hibernate")) {
            treeSet.add(str); 
        } 
 
        System.out.println("Order of objects in TreeSet :" + treeSet);
    } 
 
    // Method to calculate insertion time of 2000 objects in HashSet 
    private static void insertionTimeHashSet() 
    { 
        HashSet<Integer> hashSet = new HashSet<>(); 
        long startTime = System.nanoTime(); 
        for (int i = 0; i < 2000; i++) { 
            hashSet.add(i); 
        } 
        long endTime = System.nanoTime(); 
        System.out.println("Time taken to insert 2000 objects in HashSet (seconds): "); 
        System.out.println(endTime - startTime); 
    } 
 
    // Method to calculate insertion time of 2000 objects in LinkedHashSet 
    private static void insertionTimeLinkedHashSet() 
    { 
        LinkedHashSet<Integer> linkedHashSet = new LinkedHashSet<>(); 
        long startTime = System.nanoTime(); 
        for (int i = 0; i < 2000; i++) { 
            linkedHashSet.add(i); 
        } 
        long endTime = System.nanoTime(); 
        System.out.println("Time taken to insert 2000 objects in LinkedHashSet (seconds): "); 
        System.out.println(endTime - startTime); 
    } 
 
    // Method to calculate insertion time of 2000 objects in TreeSet 
    private static void insertionTimeTreeSet() 
    { 
        TreeSet<Integer> treeSet = new TreeSet<>(); 
        long startTime = System.nanoTime(); 
        for (int i = 0; i < 2000; i++) { 
            treeSet.add(i); 
        } 
        long endTime = System.nanoTime(); 
        System.out.println("Time taken to insert 2000 objects in TreeSet (seconds): "); 
        System.out.println(endTime - startTime); 
    } 
 
    // Method to calculate deletion time of 2000 objects from HashSet 
    private static void deletionTimeHashSet() 
    { 
        HashSet<Integer> hashSet = new HashSet<>(); 
 
        for (int i = 0; i < 2000; i++) { 
            hashSet.add(i); 
        } 
 
        long startTime = System.nanoTime();
 
        for (int i = 0; i < 2000; i++) { 
            hashSet.remove(i); 
        }
 
        long endTime = System.nanoTime(); 
        System.out.println("Time taken to delete 2000 objects from HashSet (seconds): "); 
        System.out.println(endTime - startTime); 
    } 
 
    // Method to calculate deletion time of 2000 objects from LinkedHashSet 
    private static void deletionTimeLinkedHashSet() 
    { 
        LinkedHashSet<Integer> linkedHashSet = new LinkedHashSet<>(); 
 
        for (int i = 0; i < 2000; i++) { 
            linkedHashSet.add(i); 
        } 
 
        long startTime = System.nanoTime();
 
        for (int i = 0; i < 2000; i++) { 
            linkedHashSet.remove(i); 
        }
 
        long endTime = System.nanoTime(); 
        System.out.println("Time taken to delete 2000 objects from LinkedHashSet (seconds): "); 
        System.out.println(endTime - startTime); 
    } 
 
    // Method to calculate deletion time of 2000 objects from TreeSet 
    private static void deletionTimeTreeSet() 
    { 
        TreeSet<Integer> treeSet = new TreeSet<>(); 
 
        for (int i = 0; i < 2000; i++) { 
            treeSet.add(i); 
        } 
 
        long startTime = System.nanoTime();
 
        for (int i = 0; i < 2000; i++) { 
            treeSet.remove(i); 
        }
 
        long endTime = System.nanoTime(); 
        System.out.println("Time taken to delete 2000 objects from TreeSet (seconds): "); 
        System.out.println(endTime - startTime); 
    } 
 
    public static void main(String args[]) 
    { 
        objectsOrderHashSet(); 
        objectsOrderLinkedHashSet(); 
        objectsOrderTreeSet(); 
        insertionTimeHashSet();
        insertionTimeLinkedHashSet();
        insertionTimeTreeSet();
        deletionTimeHashSet();
        deletionTimeLinkedHashSet();
        deletionTimeTreeSet();
    }  
}

Output

Order of objects in HashSet :[Java, Hibernate, Spring]
Order of objects in LinkedHashSet :[Java, Spring, Hibernate]
Order of objects in TreeSet :[Hibernate, Java, Spring]
Time taken to insert 2000 objects in HashSet (seconds):
5800855
Time taken to insert 2000 objects in LinkedHashSet (seconds):
2844478
Time taken to insert 2000 objects in TreeSet (seconds):
9928731
Time taken to delete 2000 objects from HashSet (seconds):  
1862538
Time taken to delete 2000 objects from LinkedHashSet (seconds): 
1317498 
Time taken to delete 2000 objects from TreeSet (seconds):
4296996

Java interview questions on collections