Java HashSet

The HashSet class in Java is a member of the Java Collections Framework and it extends the AbstractSet class and implements the Set interface. 
Java HashSet

Key Points About HashSet Class

Here are some key points about the Java HashSet class:

Unordered and Unsorted: 

The elements in a HashSet are not ordered or sorted. There is no guarantee that the order will remain constant over time. 

Unique Elements: 

HashSet does not allow duplicate values. It means you can only store a particular value once. If you try to add the same value again, it will replace the old value. 

Null Elements: 

HashSet allows one null value. 

Non-Synchronized: 

HashSet is non-synchronized. This means that it is not thread-safe and multiple threads can access it simultaneously. 

Underlying Data Structure: 

HashSet is implemented in terms of a hash table. It uses a mechanism called hashing to store the elements. HashSet internally uses HashMap to store the elements.

Performance: 

The add, remove, and contains methods have constant time complexity O(1). It offers constant-time performance for the basic operations (add, remove, contains, and size). 

Implements Set Interface:

HashSet implements Set Interface which means it inherits all the methods of Set Interface. 

Initial Capacity and Load Factor: 

The initial default capacity of HashSet is 16, and the default load factor is 0.75.

Create HashSet

Here is the syntax to create a HashSet class object:
        // Creating a HashSet
        HashSet<String> set = new HashSet<>();

Add Elements to HashSet

We can use add() method to add elements to the HashSet:

Here is the complete program:
import java.util.HashSet;

public class Main {
    public static void main(String[] args) {
        // Creating a HashSet
        HashSet<String> set = new HashSet<>();

        // Adding new elements to the HashSet
        set.add("Java");
        set.add("Python");
        set.add("JavaScript");

        // Displaying the HashSet elements
        for(String language : set){
            System.out.println(language);
        }
    }
} 

Output:

Java
JavaScript
Python

HashSet Contains One Null Value but Not Duplicate Values

HashSet does not allow duplicate values. It means you can only store a particular value once. HashSet allows one null value. 

Here is a simple example that demonstrates how a Java HashSet can contain no duplicates and one null value:
import java.util.HashSet;

public class HashSetExample {
    public static void main(String[] args) {
        HashSet<String> hset = new HashSet<String>();
        
        // Adding elements to the HashSet
        hset.add("Apple");
        hset.add("Mango");
        hset.add("Grapes");
        hset.add("Orange");
        hset.add("Fig");
        
        // Addition of duplicate elements
        hset.add("Apple");
        hset.add("Mango");

        // Addition of null values
        hset.add(null);
        hset.add(null);

        // Displaying HashSet elements
        System.out.println(hset);
    }
}

Output:

[null, Mango, Fig, Apple, Grapes, Orange]
This output shows that duplicate values are not allowed and order is not maintained in HashSet.

Create HashSet from Another Collection

We can use the addAll() method to add all the elements from an existing collection to a HashSet.

Creating HashSet from Collection Example:
List<Integer> list = new ArrayList<>();
list.add(5);
list.add(10);
list.add(15);
list.add(20);
list.add(25);

List<Integer> list2 = new ArrayList<>();
list2.add(3);
list2.add(6);
list2.add(9);
list2.add(12);
list2.add(15);

// Creating a HashSet from another collection (ArrayList)
Set<Integer> set = new HashSet<>(list);

// Adding all the elements from an existing collection to a HashSet
set.addAll(list2);

System.out.println(set);

Access Elements

In Java, the HashSet class does not have a get() method to access its elements as it is not an indexed collection. The order of elements in a HashSet is not guaranteed, hence, we cannot directly access an element of the HashSet. 

However, you can iterate through a HashSet to access its elements. Here's an example:
import java.util.HashSet;
import java.util.Iterator;

public class Main {
    public static void main(String[] args) {
        // Creating a HashSet
        HashSet<String> set = new HashSet<>();

        // Adding new elements to the HashSet
        set.add("Java");
        set.add("Python");
        set.add("JavaScript");

        // Accessing elements using an iterator
        Iterator<String> iterator = set.iterator();
        while(iterator.hasNext()){
            String language = iterator.next();
            System.out.println(language);
        }
    }
}

Output:

JavaScript
Java
Python
In this example, we used an Iterator to access and print every element in the HashSet. Because HashSet does not maintain any order of its elements, the output can be in any order.

Remove Elements

We can remove elements from HashSet using these methods:
  • remove(Object o): This method is used to remove a single specified element from the set.
  • removeAll(Collection c): This method is used to remove all elements from the set that are contained in the specified collection.
  • removeIf(Predicate<? super E> filter): This method is used to remove all elements from the set that satisfy the given predicate.
Here is an example that demonstrates these methods:
import java.util.HashSet;
import java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        // Creating a HashSet
        HashSet<String> set = new HashSet<>();
        set.addAll(Arrays.asList("Apple", "Banana", "Cherry", "Date", "Elderberry"));

        System.out.println("Original HashSet: " + set);

        // Using remove(Object o)
        set.remove("Cherry");
        System.out.println("\nAfter remove('Cherry'): " + set);

        // Using removeAll(Collection c)
        set.removeAll(Arrays.asList("Apple", "Banana"));
        System.out.println("\nAfter removeAll(Arrays.asList('Apple', 'Banana')): " + set);

        // Using removeIf(Predicate<? super E> filter)
        set.removeIf(fruit -> fruit.startsWith("E"));
        System.out.println("\nAfter removeIf(fruit -> fruit.startsWith('E')): " + set);
    }
}

Output:

Original HashSet: [Date, Apple, Elderberry, Cherry, Banana]

After remove('Cherry'): [Date, Apple, Elderberry, Banana]

After removeAll(Arrays.asList('Apple', 'Banana')): [Date, Elderberry]

After removeIf(fruit -> fruit.startsWith('E')): [Date]

Iterate or Loop Through HashSet

The following example shows different ways of iterating over a HashSet
  • Iterate over a HashSet using Java 8 forEach and lambda expression.
  • Iterate over a HashSet using iterator().
  • Iterate over a HashSet using iterator() and Java 8 forEachRemaining() method.
  • Iterate over a HashSet using a simple for-each loop.

iterator()

Set<String> list = new HashSet<>();
list.add("element 1");
list.add("element 2");
list.add("element 3");
list.add("element 4");

// using Iterator
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
    String str = iterator.next();
    System.out.println(" only forward direction ---" + str);
}

Advance for() loop

// Using advanced for loop
for (String str : list) {
    System.out.println(" only forward direction ---" + str);
}

forEachRemaining()

// Java 8
list.forEachRemaining(str -> System.out.println(" only forward direction ---" + str));

forEach()

// Java 8
list.forEach(str -> System.out.println(" only forward direction ---" + str));

HashSet with User-defined objects

This example shows how to create a HashSet of user-defined objects.
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;

class Customer {
    private long id;
    private String name;

    public Customer(long id, String name) {
        this.id = id;
        this.name = name;
    }

    public long getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    // Two customers are equal if their IDs are equal
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Customer customer = (Customer) o;
        return id == customer.id;
    }

    @Override
    public int hashCode() {
        return Objects.hash(id);
    }

    @Override
    public String toString() {
        return "Customer{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}

public class HashSetUserDefinedObjectExample {
    public static void main(String[] args) {
        Set<Customer> customers = new HashSet<>();
        customers.add(new Customer(1, "Ramesh"));
        customers.add(new Customer(2, "Pramod"));
        customers.add(new Customer(3, "Sanjay"));

        System.out.println(customers);
    }
}
Output
[Customer{id=1, name='Ramesh'}, Customer{id=2, name='Pramod'}, Customer{id=3, name='Sanjay'}]

Make HashSet Thread-Safe

In Java, HashSet is not thread-safe, which means if it is used in a multi-threaded environment, then multiple threads can access and modify it simultaneously leading to data inconsistency. 

However, you can make a HashSet thread-safe by using the Collections.synchronizedSet() method. This method returns a synchronized (thread-safe) set backed by the specified set. Here is an example:
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

public class Main {
    public static void main(String[] args) {
        Set<String> set = new HashSet<String>();
        set.add("Apple");
        set.add("Banana");
        set.add("Cherry");

        Set<String> synchronizedSet = Collections.synchronizedSet(set);

        // Now you can use synchronizedSet in a multi-threaded environment safely
    }
}

Conclusion

Congratulations folks! In this article, you learned what is a HashSet, key points about HashSet, how to create a HashSet, how to add elements to a HashSet, how to remove elements from the HashSet, how to iterate over a HashSet, and how to create a HashSet of user-defined objects. 

Comments

  1. the usage of

    forEachRemaining()
    // Java 8
    list.forEachRemaining(str -> System.out.println(" only forward direction ---" + str));

    may not correct

    ReplyDelete
  2. if that have to instead of -> ?

    Iterator i = list.iterator();
    i.next();
    i.forEachRemaining(System.out::println);

    ReplyDelete

Post a Comment

Leave Comment