Java Collections framework- A complete guide | Collections framework in java


In java, a group of objects can be treated as a single unit using the collections framework. Arbitrary objects can be stored, retrieved, and manipulated as elements of collections. Collections framework in java provides a set of standard utility classes that facilitates managing such arbitrary groups of objects. This framework is provided by 'java.util' package that comprises of three components:


-Core collection interfaces

-Implementing classes/concrete classes that implement the core interfaces

-Utility methods that can be used to perform various operations on collections such as sorting, searching, traversing, and creating custom collections.



What are core collection interfaces and their implementing classes in java?


The core collection interfaces are - Collection, Set, List, SortedSet, Map, and SortedMap. The below image depicts the inheritance hierarchy of these core interfaces.

Core collection interfaces

The below table illustrates the concrete implementing classes of the core interfaces:

Core collection interfaces Concrete/implementing classes
Collection N/A
Set HashSet
LinkedHashSet
SortedSet TreeSet
List ArrayList
Vector
LinkedList
Map HashMap
Hashtable
LinkedHashMap
SortedMap TreeMap



1. Collection interface in Java


A basic or skeleton interface that defines the normal operations that allow a collection of objects to be maintained and handled as a single unit. It specified the contract that all collections should implement. Some of the operations specified by the Collection interface that can be performed on the content of a collection:

int size()
boolean isEmpty()
boolean contains(Object element)
boolean add(Object element)
boolean remove(Object element)


Below operations are performed on a collection as a single unit:

boolean containsAll(Collection c)
boolean addAll(Collection c)
boolean removeAll(Collection c)
boolean retainAll(Collection c)
void clear()



2. Set interface in Java


The Set interface extends the Collection interface and represents a set of unique elements i.e. A Set interface does not allow duplicate elements. HashSet is the implementing class (concrete classes) of Set interface.


How to create a Set in java?


A set can be created by using any one of the implementing classes of the Set interface i.e. HashSet or LinkedHashSet.

Set s=new HashSet();

OR

Set s2=new LinkedHashSet();

The elements in a set can be added by using add() method that accepts elements in the form of objects. The below code snippet, will add elements in a HashSet:

s.add(1);
s.add("hello");
s.add("world");
s.add(20);
s.add(obj1);
s.add(obj2);
s.add("jayesh");


Here obj1 and obj2 are objects of a random custom class. The below code snippet, will add elements in a LinkedHashSet:

s2.add("first");
s2.add("second");
s2.add("third");
s2.add("fourth");
s2.add("fifth");



How to iterate the elements in a set?


The iterator() method of Set interface returns an iterator over the elements in the set. The elements are returned in no particular order.

Iterator itr=s.iterator();
while(itr.hasNext()){
System.out.println("Set elements are -->"+itr.next().toString());
}



What is the difference between HashSet and LinkedHashSet?


A HashSet does not necessarily maintain the ordering of the elements but its subclass LinkedHashSet maintains the ordering of the elements and guarantees insertion order. The below image illustrates the output of traversing the HashSet and LinkedHashSet respectively.


output of traversing HashSet and LinkedHashSet

3. SortedSet interface in Java


SortedSet interface extends Set interface and defines the functionality for maintaining a set in which the elements are stored in some sorted order. SortedSet interface sorts the elements of a Set in a specific order. TreeSet is the implementing class of the SortedSet interface.

SortedSet ss=new TreeSet();
ss.add("Hi");
ss.add("java");
ss.add("ruby");
ss.add("python");
ss.add("php");
ss.add("1930");

This interface has some specific methods that are defined in its implementing class TreeSet. For instance - headSet(Object toElement), tailSet(Object fromElement), and subSet(Object fromElement, Object toElement) returns a SortedSet that is derived from the current SortedSet. The returned sorted set is nothing but a view portion of the original sorted set and any change made to the returned set is reflected in the original sorted set and vice-vera.

headSet(Object toElement): The headSet(Object toElement) method returns a view of the portion of the existing set whose elements are less than 'toElement'.
SortedSet ss2=ss.headSet("java") : Here 'ss2' is the returned sorted set which is nothing but the portion of the original sorted set 'ss'. This portion has view till elements falling before "java". The returned set is backed by the original set, so any changes made to the returned set are reflected in this set, and vice-versa. i.e. Any change made to 'ss2' will be reflected in 'ss' and vice-versa. For instance, the remove operation on the returned set will be reflected in the original sorted set.

ss2.remove("Hi");
Iterator originalSSItr=ss.iterator();
while(originalSSItr.hasNext())
{
System.out.println("original sortedset after remove operation-->" +originalSSItr.next().toString());
}

The below image shows the console output where the changes made to the returned sorted set is reflected in the original sorted set.

changes made to the returned sorted set reflected in the original sorted set

tailSet(Object fromElement): Similarly, the tailSet(Object fromElement) method returns a view of the portion of the existing set whose elements are greater than or equal to 'fromElement'. The below code snippet creates a tail set of the original sorted set. This portion has a view of all the elements starting from "java". Here also, any changes made to the returned set are reflected in the original set and vice-versa.

SortedSet ss3=ss.tailSet("java");
Iterator itrForTailset=ss3.iterator();
while(itrForTailset.hasNext()) {
System.out.println("returned tailet is-->"+itrForTailset.next().toString());
}


tailset method for sorted set

subSet(Object toElement, Object fromElement): Lastly the subSet(Object toElement, Object fromElement) returns a view of the portion of this set whose elements are in the range from 'fromElement', to 'toElement'. Here, the 'fromElement' is included in the returned set but the 'toElement' is excluded in the returned set. If 'fromElement' and 'toElement' are equal, then the returned set is empty.



4. List interface in Java


The List interface extends the Collection interface to maintain a sequence of elements that need not be unique. A list can contain duplicate elements but the elements in a list are ordered. In other words, Lists are collections that maintain their elements in order. Each element in a list has a position, and the position of an element can be changed as elements are added or deleted from the list. Three implementing classes of List interface are -

- ArrayList

- LinkedList

- Vector

ArrayList and Vector classes are implemented using dynamically resizable arrays which provide fast random access and quick list traversal. The Vector class is thread-safe that means concurrent calls to the vector won't compromise its integrity. The implementation of LinkedList on the other hand uses a doubly-linked list that makes the insertion and deletion of elements very efficiently.



5. Map interface in Java


A skeleton interface that defines operations for maintaining mappings of keys to values. A Map also does not allow the duplication of keys. The keys in the Map are unique. The combination of the key, value pair is called an entry. Each key in a Map maps to a single value at the most. Thus there is a many-to-one relation between keys and values. For e.g. in a vehicle registration number map, a regional transport office awards registration numbers to many vehicles but each vehicle has only one registration number. Another most important point to remember for a Map is, both keys and values must be objects therefore any primitive value must be wrapped in its respective wrapper object before they are being put on a map. A map is not a collection of elements. It defines mappings from keys to values therefore a Map interface does not extend the Collection interface.



How to create a Map in Java?


As we know that the HashMap is the implementing class of the Map interface. So, a reference variable for Map pointing a HashMap object can be implemented as below.

Map map=new HashMap();

Now the elements in the form of key, value pairs can be put with the help of put() method. The put() method associates the specified value with the specified key in this map. map.put(1, "amit");

map.put(2, "jai");

map.put(3, "ravi");

map.put(4, "ratan");

map.put(5, "raj");

map.put(6, "raju");

map.put(7, "sham");

map.put(8, "raj");


Alternatively, you can use other implementing classes of Map interface like - Hashtable, and LinkedHashMap.

Map map2=new Hashtable();

OR

Map map3=new LinkedHashMap();

The basic difference between HashMap, Hashtable, and LinkedHashMap classes is that the HashMap and Hashtable implement unordered maps. Whereas LinkedHashMap implements ordered maps. The HashMap class is not thread-safe and allows one null key, whereas the Hashtable class is thread-safe and allows only non-null keys and values. Use the HashMap class if ordering is not important.



How to traverse elements in a Map?


The set is backed by the map, so changes to the map are reflected in the set, and vice-versa. The entrySet() method of the Map interface returns a Set view of the mappings contained in this map. And this set now can be iterated through an Iterator. The above map can be iterated as below:

Set set=map.entrySet();
Iterator itr=set.iterator();
while(itr.hasNext())
{
System.out.println(itr.next().toString());
}