Java HashSet

High-performance Set implementation using hash table

⚡ What is HashSet?

HashSet is the most popular Set implementation that uses hash table for storage, providing constant-time performance for basic operations like add, remove, and contains.


// Creating and using HashSet
import java.util.HashSet;

HashSet<String> cities = new HashSet<>();
cities.add("New York");
cities.add("London");
cities.add("Tokyo");
cities.add("New York");    // Duplicate ignored

System.out.println(cities);
System.out.println("Contains London: " + cities.contains("London"));
                                    

Output:

[Tokyo, New York, London]
Contains London: true

HashSet Advantages

🚀

Fast Operations

O(1) average time for add, remove, contains

set.contains("item"); // Very fast
🎯

Unique Elements

Automatically handles duplicates

set.add("duplicate"); // Ignored if exists
💾

Memory Efficient

Efficient storage using hash table

// Optimized internal structure
🔄

No Ordering

Elements stored in hash order

// Order not guaranteed

🔹 Creating HashSet

Different ways to create and initialize HashSet:

import java.util.*;

public class HashSetCreation {
    public static void main(String[] args) {
        // 1. Empty HashSet
        HashSet<String> set1 = new HashSet<>();
        
        // 2. HashSet with initial capacity
        HashSet<String> set2 = new HashSet<>(20);
        
        // 3. HashSet with initial capacity and load factor
        HashSet<String> set3 = new HashSet<>(20, 0.8f);
        
        // 4. HashSet from another collection
        List<String> list = Arrays.asList("A", "B", "C", "A");
        HashSet<String> set4 = new HashSet<>(list);
        
        // 5. Using Set interface (recommended)
        Set<String> set5 = new HashSet<>();
        
        // 6. Initialize with values (Java 9+)
        Set<String> set6 = new HashSet<>(Set.of("X", "Y", "Z"));
        
        // 7. Using Collections utility
        Set<String> set7 = new HashSet<>();
        Collections.addAll(set7, "P", "Q", "R");
        
        System.out.println("Set4 (from list with duplicates): " + set4);
        System.out.println("Set6 (initialized): " + set6);
        System.out.println("Set7 (using Collections.addAll): " + set7);
    }
}

Output:

Set4 (from list with duplicates): [A, B, C]
Set6 (initialized): [X, Y, Z]
Set7 (using Collections.addAll): [P, Q, R]

🔹 HashSet Methods

Essential HashSet operations with examples:

import java.util.*;

public class HashSetMethods {
    public static void main(String[] args) {
        HashSet<Integer> numbers = new HashSet<>();
        
        // Adding elements
        numbers.add(10);
        numbers.add(20);
        numbers.add(30);
        numbers.add(20);        // Duplicate - ignored
        
        System.out.println("After adding: " + numbers);
        System.out.println("Size: " + numbers.size());
        
        // Checking elements
        System.out.println("Contains 20: " + numbers.contains(20));
        System.out.println("Contains 40: " + numbers.contains(40));
        System.out.println("Is empty: " + numbers.isEmpty());
        
        // Adding multiple elements
        numbers.addAll(Arrays.asList(40, 50, 30)); // 30 is duplicate
        System.out.println("After addAll: " + numbers);
        
        // Removing elements
        boolean removed = numbers.remove(20);
        System.out.println("Removed 20: " + removed);
        System.out.println("After removal: " + numbers);
        
        // Remove multiple elements
        numbers.removeAll(Arrays.asList(40, 50));
        System.out.println("After removeAll: " + numbers);
        
        // Keep only specific elements
        HashSet<Integer> toKeep = new HashSet<>(Arrays.asList(10, 30, 60));
        numbers.retainAll(toKeep);
        System.out.println("After retainAll: " + numbers);
        
        // Clear all elements
        HashSet<Integer> copy = new HashSet<>(numbers);
        copy.clear();
        System.out.println("After clear: " + copy);
        System.out.println("Original: " + numbers);
    }
}

Output:

After adding: [20, 10, 30]
Size: 3
Contains 20: true
Contains 40: false
Is empty: false
After addAll: [50, 20, 40, 10, 30]
Removed 20: true
After removal: [50, 40, 10, 30]
After removeAll: [10, 30]
After retainAll: [10, 30]
After clear: []
Original: [10, 30]

🔹 HashSet Performance

Understanding HashSet's performance characteristics:

Time Complexity:

  • add(element): O(1) average, O(n) worst case
  • remove(element): O(1) average, O(n) worst case
  • contains(element): O(1) average, O(n) worst case
  • size(): O(1)
  • isEmpty(): O(1)

Space Complexity:

  • Storage: O(n) where n is number of elements
  • Load Factor: Default 0.75 (75% capacity before resize)
// Performance demonstration
HashSet<String> largeSet = new HashSet<>();

// Adding 1 million elements - still fast!
for (int i = 0; i < 1000000; i++) {
    largeSet.add("Element" + i);
}

// Fast lookup even in large set
long startTime = System.nanoTime();
boolean found = largeSet.contains("Element500000");
long endTime = System.nanoTime();

System.out.println("Found: " + found);
System.out.println("Search time: " + (endTime - startTime) + " nanoseconds");
System.out.println("Set size: " + largeSet.size());

🔹 HashSet vs Other Collections

When to choose HashSet over other collections:

Choose HashSet when:

  • You need to ensure unique elements
  • Fast lookup/membership testing is important
  • You don't need elements in any specific order
  • You frequently check if elements exist

Don't choose HashSet when:

  • You need elements in insertion order (use LinkedHashSet)
  • You need elements sorted (use TreeSet)
  • You need indexed access (use ArrayList)
  • You allow duplicate elements (use List)

🔹 Practical HashSet Examples

Real-world applications of HashSet:

import java.util.*;

public class HashSetExamples {
    public static void main(String[] args) {
        // Example 1: Track unique visitors
        HashSet<String> uniqueVisitors = new HashSet<>();
        String[] visitors = {"user1", "user2", "user1", "user3", "user2", "user4"};
        
        for (String visitor : visitors) {
            if (uniqueVisitors.add(visitor)) {
                System.out.println("New visitor: " + visitor);
            } else {
                System.out.println("Returning visitor: " + visitor);
            }
        }
        System.out.println("Total unique visitors: " + uniqueVisitors.size());
        
        // Example 2: Find unique words in text
        String text = "the quick brown fox jumps over the lazy dog the fox is quick";
        String[] words = text.split(" ");
        HashSet<String> uniqueWords = new HashSet<>(Arrays.asList(words));
        
        System.out.println("Original words: " + words.length);
        System.out.println("Unique words: " + uniqueWords.size());
        System.out.println("Unique word list: " + uniqueWords);
        
        // Example 3: Check permissions
        HashSet<String> userPermissions = new HashSet<>(
            Arrays.asList("read", "write", "delete")
        );
        
        String[] requestedActions = {"read", "write", "execute", "delete"};
        for (String action : requestedActions) {
            if (userPermissions.contains(action)) {
                System.out.println("✅ Permission granted for: " + action);
            } else {
                System.out.println("❌ Permission denied for: " + action);
            }
        }
    }
}

Output:

New visitor: user1
New visitor: user2
Returning visitor: user1
New visitor: user3
Returning visitor: user2
New visitor: user4
Total unique visitors: 4
Original words: 13
Unique words: 9
Unique word list: [over, fox, dog, the, lazy, brown, is, quick, jumps]
✅ Permission granted for: read
✅ Permission granted for: write
❌ Permission denied for: execute
✅ Permission granted for: delete

🧠 Test Your Knowledge

What is the average time complexity of the contains() method in HashSet?