Tuesday, June 20, 2023

Demystifying Java Collections: Set, HashSet, and LinkedHashSet

java,Collection Framework,set,hashset,programming,software development,technology
The Collection Framework offers a set of interfaces and classes for storing and manipulating groups of objects. The Set interface, along with its common implementations such as HashSet and LinkedHashSet, is one of the most commonly used types in this framework.

Set(I)

The Set is the Collection's child interface. Set(I) contains no new methods. As a result, we can call Collection interface methods.
java,Collection Framework,ArrayList,List,set,hashset,treemap

Here are some scenarios in which a Set collection could be useful:
  • If you have a collection of elements that may contain duplicates, you can use a Set to remove the duplicates. Simply add all of the elements to a Set and then retrieve the unique elements from the Set.
  • When comparing the equality of two collections of elements, we can use the Set. You can create two Set objects from the two collections and then compare their equality.
  • When we want to perform operations on a collection of objects without creating duplicates, we can use a Set collection. Set operations such as union, intersection, and difference are possible.

HashSet

HashSet is a class that extends AbstractSet and implements the Set interface. This means that HashSet inherits all of AbstractSet's methods and implements the Set interface's required methods. Internally, HashSet stores elements in a HashTable. Each element is stored in the hash table as a key, with the value.

Java first determines the element's hash code using its hashCode() method before inserting the element into a HashSet. The new element is compared to the existing element using the equals() method. The new element is not included in the set if they are equal. The new element is included in the set if they are not equal. HashSet accepts NULL elements. In fact, since a hash set forbids duplication, there can only be one null element in a hash set.

👉 Here are some HashSet constructors:
// Creates a new HashSet object that is empty and has an initial capacity of 16 
// and a fill ratio or load factor of 0.75 by default.
HashSet hashSet = new HashSet();

// Creates an empty HashSet object with the specified initial capacity 
// and a fill ratio or load factor of 0.75 by default.
HashSet hashSet = new HashSet(int capacity);

// Creates a new HashSet object with the specified initial capacity and load factor or fill capacity.
HashSet hashSet = new HashSet(int capacity, float loadFactor);

// Creates an empty HashSet object from a Collection object. This converts the Collection object to a HashSet.
HashSet hashSet = new HashSet(Collection collection);


👉 Here's some code that shows how to use Set and HashSet:
import java.util.*;
public class HashSetDemo {
    public static void main(String[] args) {
        Set _set = new HashSet();
        _set.add("John Snow");
        _set.add(41);
        _set.add("john@gmail.com");
        _set.add("Japan");
        System.out.println("Size of the Set object : " + _set.size());

        Object[] objects = _set.toArray();
        for (int i = 0; i < objects.length; i++) {
            System.out.println(objects[i]);
        }

        if (_set.contains(41)) {
            System.out.println("Set contains specified element.");
        }
    }
}
In the preceding code snippet, we created a HashSet object and assigned it to a Set. We can do this because HashSet is the implementation class for the Set interface. The Set object is then filled with elements of various types. To convert the Set object into an array object, we use the toArray() method in line 13. HashSet inherited the toArray() method from the Collection interface. The index is then used to print the array values.

When we run this code, we can see that the elements are not printed in the order that we entered them. Despite the fact that we print the elements using the index. This means that elements in HashSet are not kept in order.

👉 Here's another HashSet code snippet with a Generic type:
import java.util.*;
public class HashSetGenericDemo {
    public static void main(String[] args) {
        Set<String> _set = new HashSet<>();
        _set.add("John Snow");
        // _set.add(41);
        _set.add("41");
        _set.add("john@gmail.com");
        _set.add("Product Manager");
        _set.add("813 Howard Street");
        System.out.println(_set);

        System.out.println(_set.add("CA 12345"));
        System.out.println(_set.add("CA 12345"));

        Set<String> anothetSet = new HashSet<>();
        anothetSet.add("Alex White");
        anothetSet.add("42");
        anothetSet.add("Senior Manager");
        anothetSet.add("alex@gmail.com");
        anothetSet.add("159 Howard Street");

        _set.addAll(anothetSet);
        System.out.println(_set);
    }
}
We create a generic HashSet of type String and populate it with String elements. To store other primitive data types, we must use the generic type.

In lines 14 and 15, we attempted to add the same element to the HashSet. If we run the code, we can see that the output for line 14 is true, but the output for line 15 is false. Because the element isn't in the HashSet, the add() method returns true for line 14. However, because the element is already present in the HashSet, line 15 returns false, indicating that we cannot add duplicate elements to the HashSet.

In line 17, we added another HashSet. In line 24, use the addAll() method to insert this new HashSet into our previous HashSet.


👉 Here are some specific scenarios where a Set may be useful. If you have a collection of elements that may contain duplicates, you can use a Set to remove the duplicates. Simply add all of the elements to a Set and then retrieve the unique elements from the Set.
import java.util.*;
public class HashSetDuplicateDemo {
    public static void main(String[] args) {
        // LIST WITH DUPLICATE NAMES
        List<String> nameList = Arrays.asList("Jane", "Amanda", "Joshua", "Megan", "Jane", 
        		"Emily", "Scott", "Joshua", "Rebecca", "Daniel", "Victoria", "Megan", "Rebecca");
        System.out.println("Original name list " + nameList + " of size " + nameList.size());
        
        // CREATE A HASHSET OBJECT WITH THE LIST
        Set<String> _set = new HashSet<String>(nameList);
        System.out.println("Unique name list " + _set + " of size " + _set.size());
    }
}


👉 We can use Set to see if two collections have any common elements, which indicates an intersection. From the two collections, we can create HashSet objects and then use the retainAll() method to find the intersection of the two collections. If the resulting set is empty, the two collections share no elements; otherwise, the two collections share elements. Here's an example:
import java.util.*;
public class HashSetIntersectionDemo {
    public static void main(String[] args) {
        List<String> nameListOne = Arrays.asList("Jane", "Amanda", "Joshua", "Megan");
        List<String> nameListTwo = Arrays.asList("Emily", "Scott", "Rebecca", "Daniel", "Victoria");
        List<String> nameListThree = Arrays.asList("Jane", "Emily", "Joshua", "Rebecca","Victoria", "Amanda");

        // Set<String> _setOne = new HashSet<String>(nameListOne);
        // Set<String> _setTwo = new HashSet<String>(nameListTwo);
        // Set<String> _setThree = new HashSet<String>(nameListThree);

        Set<String> _resultOne = new HashSet<String>(nameListOne);
        _resultOne.retainAll(nameListTwo);
        System.out.println(_resultOne.isEmpty() == true ? "No common element found in the HashSets."
                : "HashSets has common elements.");
        System.out.println("Result has " + _resultOne + " elements of size " + _resultOne.size());
        System.out.println();

        Set<String> _resultTwo = new HashSet<String>(nameListTwo);
        _resultTwo.retainAll(nameListThree);
        System.out.println(_resultTwo.isEmpty() == true ? "No common element found in the HashSets."
                : "HashSets has common elements.");
        System.out.println("Result has " + _resultTwo + " elements of size " + _resultTwo.size());
    }
}


👉 Using the Set, we can also perform the union operation. If we have one or more collection objects with duplicate elements, we can use these collections to create a single Set object and the duplicate elements will be removed automatically. This means that we're making a union out of the collection objects. Here's an illustration.
import java.util.*;
public class HashSetUnionDemo {
    public static void main(String[] args) {
        List<String> nameListOne = Arrays.asList("Jane", "Amanda", "Joshua", "Megan");
        List<String> nameListTwo = Arrays.asList("Emily", "Scott", "Rebecca", "Daniel", "Victoria");
        List<String> nameListThree = Arrays.asList("Jane", "Emily", "Joshua", "Rebecca","Victoria", "Amanda");

        Set<String> _resultOne = new HashSet<String>(nameListOne);
        _resultOne.addAll(nameListTwo);
        _resultOne.addAll(nameListThree);
        System.out.println("Union has " + _resultOne + " elements of size " + _resultOne.size());
    }
}


👉 Set can be used to store a collection of unique objects. Assume you have the following Booking objects:
import java.util.*;
public class HashSetObjectDemo {
    public static void main(String[] args) {
        List<Booking> bookings = new ArrayList<>();
        bookings.add(new Booking(10, "Joshua")); bookings.add(new Booking(15, "Victoria"));
        bookings.add(new Booking(19, "Rebecca")); bookings.add(new Booking(8, "Amanda"));
        bookings.add(new Booking(20, "Victoria")); bookings.add(new Booking(19, "Rebecca"));
        System.out.println("No of Booking List " + bookings.size());

        Set<Booking> setBooking = new HashSet<Booking>(bookings);
        System.out.println("No of Booking Set " + setBooking.size());
        for (Booking booking : setBooking) {
            System.out.println(booking);
        }
    }
}
class Booking {
    int seatNo;
    String name;

    public Booking() { }

    public Booking(int seatNo, String name) {
        this.seatNo = seatNo;
        this.name = name;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + seatNo;
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Booking other = (Booking) obj;
        if (seatNo != other.seatNo)
            return false;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }

    @Override
    public String toString() {
        return "Booking [seatNo=" + seatNo + ", name=" + name + "]";
    }
}
In this example, the Booking class overrides the equals() and hashCode() methods so that two Booking objects are considered equal if they have the same name and seatNo. The Set ensures that there are no duplicate Booking objects in the collection.


LinkedHashSet

LinkedHashSet is a class that extends HashSet and implements the Set interface. In addition to the hash table, the LinkedHashSet keeps a linked list. This linked list allows the elements to be iterated in the order they were added to the set. Duplicates are not allowed in LinkedHashSet.

👉 Here's an example of how LinkedHashSet can be used:
import java.util.*;
public class LinkedHashSetDemo {
    public static void main(String[] args) {
        Set<String> linkedHashSet = new LinkedHashSet<>();
        linkedHashSet.add("John Snow");
        linkedHashSet.add("Peter Johnson");
        linkedHashSet.add("Madison Hernandez");
        linkedHashSet.add("John Snow");
        linkedHashSet.add("Audrey Davis");
        linkedHashSet.add("Victoria Davis");
        linkedHashSet.add("Isaac Thompson");
        linkedHashSet.add("Chloe Martinez");
        System.out.println("LinkedHashSet has " + linkedHashSet + " elements of size " + linkedHashSet.size());

        linkedHashSet.remove("Audrey Davis");
        System.out.println("\nAfter the removal, LinkedHashSet has " + linkedHashSet + " elements of size " + linkedHashSet.size());

        List<String> nameList = Arrays.asList("Daniel Hall", "Madison Hernandez", "Rebecca Turner", "Isabelle Taylor");
        linkedHashSet.addAll(nameList);
        System.out.println("\nAfter the addition of new collection, LinkedHashSet has " + linkedHashSet + " elements of size " + linkedHashSet.size());
        System.out.println();
    }
}
In the example above, the elements are printed in the same order in which they were added in line 13, and the duplicate element "John Snow" is removed from the LinkedHashSet object. We removed an element from the LinkedHashSet in line 15. In line 19, we added a new list of elements to the set, which includes some common elements from the LinkedHashSet object. When we print the elements, we can see that the list object's duplicate elements are ignored. 


Happy coding!!! 😊
in


No comments:

Post a Comment

Popular posts