Vasyl Malik
Senior Java Developer at CodeGym

Collections in Java

Published in the Java Developer group

What is Collection in Java?

A collection in java is represented as a container that groups all the elements into a single unit. For example, a mail folder (group of emails), a telephone directory (mapping of names to phone numbers).

What is a Framework?

A framework is a basic foundation or layout on which you start working by using the different classes and interfaces provided. For example, Laravel is one of the most famous PHP frameworks that provides a basic skeleton for your application.

What is the Collections Framework in Java?

All objects are grouped into a single object along with an architecture that represents and provides different methods for manipulating collections. So Collections framework in Java provides different data structures already implemented for storing data and methods, to manipulate them with features such as sorting, searching, deletion, and insertion. For example, you want to implement a system for some random company to improve service for their customers, based on the first come first serve basis. This is also known as a FIFO (first in first out) implementation. Now we need to implement this data structure and then use it to achieve our goal. The Collections framework provides us with a Queue interface which we only need to import rather than implement, then use it, and we are done. Implementation: You can import all of the collections by using the following line:

import java.util.*;
If you want to import a specific collection then use the exact package name, such as:

import java.util.LinkedList;

Benefits of Collections Framework in Java

It has the following benefits.
  1. Already Implemented (time-saving).
  2. Performance Efficiency (speed and quality).
  3. Reduces effort to learn and use new APIs.

What’s the Hierarchy of Collection Framework?

Now let's see the collections hierarchy but first, we need to know the essential components of this framework.
  1. Interfaces
  2. Classes (implementation)
  3. Algorithms

Hierarchy of Collection Framework

Collections in Java - 1For your understanding:
  1. Collection, Set, Queue, and List all are interfaces. Set, Queue and List are extended by the Collection interface.
  2. PriorityQueue, HashSet, LinkedList, and Stack all are classes or the implementation of these interfaces.
  3. It is not mandatory that a class implements just one interface. LinkedList also implements the Deque interface, for example.

Types Of Collections

Java collections framework has a lot of types of collections in it to reduce our efforts. Here is a list of some of the collections:
  1. ArrayList Class
  2. LinkedList Class
  3. List Interface
  4. Set Interface
  5. Queue Interface
  6. Map Interface
  7. PriorityQueue Class
  8. HashMap Class
  9. Comparable Interface
  10. LinkedHashMap Class
  11. TreeMap Class
  12. HashTable

Collection Interfaces

Here we will discuss some common collection interfaces and then some methods implemented by the classes.

Collection Interface

This is a basic foundation for the Collections framework as it provides all the necessary methods for implementation. The Map is the only data structure that does not implement it but the remaining all implement its methods. This interface has methods for knowing the size of the collection, and whether an object exists in the collection, adding or removing objects from the collection.

Iterable Interface

It is the root interface for the Collections framework as it is extended by the Collection interface which is implemented by all classes. It returns an iterator for the specific collection to iterate over it.

Queue Interface

Queue is used to hold the elements but they can not be processed. Implementing the basic collection operations, it also provides additional insertion and extraction methods.

Set Interface

Set is used to hold unique elements in it. It never contains duplicate elements and models the mathematical set abstraction to represent the sets such as processes running on a machine.

List Interface

List is an ordered collection sometimes called a sequence which can hold duplicate elements in it. It provides control to the user for updating or removing a specific element, inserting an element at a specific point by using its integer index value. LinkedList and ArrayList are implementation classes of the List interface.

Deque Interface

Deque stands for the double-ended queue which means that we can perform operations on both ends. We can insert and remove elements from both ends. The Deque interface extends the queue interface. ArrayDeque and LinkedList both implement the Deque interface. It provides methods for insertion, deletion, and examining the instance from both ends.

Map Interface

Map interface is also part of the Collections framework but it does not extend the Collection interface. It is used to store key-value pairs. Its main implementations are HashMap, TreeMap, and LinkesHashMap which are similar in certain aspects to HashSet, TreeSet, and LinkedHashSet. It always contains unique keys but the values can be duplicated. It is useful when you need to add, delete, or search for an item based on a key. It provides us with basic methods such as put, get, remove, size, empty, and so on.

Common Methods of these Interfaces

Now we will look at some common methods provided for the implementation of different classes in this framework except the Map interface.
Methods Description
public boolean add(E e) Used to insert an element into the collection
public boolean remove(Object element) Used to remove an element from the collection
public int size() Returns the number of elements in a collection
public boolean contains(Object element) Used to search for an element
public boolean isEmpty() Checks if the collection is empty
public boolean equals(Object element) Checks for equality

Collection Classes

As we know the framework has different interfaces which are implemented by many classes inside it. Now let's have a look at some commonly used classes.

LinkedList

It is the most commonly used data structure that implements a doubly linked list to store the elements inside it. It can store duplicate elements. It implements the Dequeue interface extended by the Queue interface and the List interface. It is not synchronized. Now let’s see how to solve our problem discussed above (the FIFO concept) using LinkedList. The problem is to serve the customers in a manner they arrive i.e first in first out.

Example


import java.util.*;
 
public class LinkedListExample {
    public static void main(String[] args) {
        Queue<String> customerQueue = new LinkedList<String>();
        //Adding customers to the Queue as they arrived
        customerQueue.add("John");
        customerQueue.add("Angelina");
        customerQueue.add("Brooke");
        customerQueue.add("Maxwell");
 
        System.out.println("Customers in Queue:"+customerQueue);
        //element() => returns head of the queue
        //we will see our first customer and serve him
        System.out.println("Head of the queue i.e first customer: "+customerQueue.element());
        //remove () method =>removes first element(customer) from the queue i.e the customer is served so remove him to see next
        System.out.println("Element removed from the queue: "+customerQueue.remove());
        //poll () => removes and returns the head
        System.out.println("Poll():Returned Head of the queue: "+customerQueue.poll());
        //print the remaining customers in the Queue
        System.out.println("Final Queue:"+customerQueue);
    }
}

Output

Customers in Queue:[John, Angelina, Brooke, Maxwell] Head of the queue i.e first customer: John Element removed from the queue: John Poll():Returned Head of the queue: Angelina Final Queue:[Brooke, Maxwell]

ArrayList

It simply implements the List interface. It maintains the insertion order and uses a dynamic array to store elements of different data types. Elements can be duplicated. It is also non-synchronized and can store null values. Now let’s see its different methods... These are useful when we do not know how many records or elements we need to insert. Let’s take an example of a library where we don’t know how many books we have to keep. So whenever we have a book, we need to insert it into ArrayList.

Example


public class ArrayListExample {
	public static void main(String args[]) {
		
		// Creating the ArrayList
		ArrayList<String> books = new ArrayList<String>();
		
		// Adding a book to the list
		books.add("Absalom, Absalom!");
		// Adding a book in array list
		books.add("A Time to Kill");
		// Adding a book to the list
		books.add("The House of Mirth");
		// Adding a book to the list
		books.add("East of Eden");
		// Traversing the list through Iterator
		Iterator<String> itr = books.iterator();
		while (itr.hasNext()) {
			System.out.println(itr.next());
		}
	}
}

Output

Absalom, Absalom! A Time to Kill The House of Mirth East of Eden

HashSet

It implements the Set interface and never contains duplicate values. It implements the hash table for storing the values. It also allows null values. It never maintains the insertion order but provides the constant time performance for add, remove, size, and contains methods. It is best for search operations and it is not synchronized.

Example


import java.util.*;  
class HashSetExample{  
    public static void main(String args[]){  
        //creating HashSet and adding elements to it  
        HashSet<Integer> hashSet=new HashSet();  
        hashSet.add(1);    
        hashSet.add(5);    
        hashSet.add(4);   
        hashSet.add(3);  
        hashSet.add(2);  
        //getting an iterator for the collection
        Iterator<Integer> i=hashSet.iterator(); 
        //iterating over the value 
        while(i.hasNext())  {  
            System.out.println(i.next());  
        }  
    }  
}

Output

1 2 3 4 5
As you can see it does not maintains the insertion order.

ArrayDeque

It implements the Deque interface so it allows operations from both ends. It does not allow null values. It is faster than Stack and LinkedList when implemented as Stack and LinkedList. ArrayDeque has no size restrictions as it grows and shrinks as per the requirements. It is unsynchronized, meaning it is not thread-safe. To keep it thread-safe we have to implement some external logic.

Example


import java.util.*;  
public class ArrayDequeExample {  
   public static void main(String[] args) {  
       //creating Deque and adding elements  
       Deque<String> deque = new ArrayDeque<String>();  
       //adding an element
       deque.add("One"); 
       //adding an element at the start
       deque.addFirst("Two");     
       //adding an element at the end
       deque.addLast("Three");    
       //traversing elements of the collection  
       for (String str : deque) {  
            System.out.println(str);  
       }  
   }  
}

Output

Two One Three

HashMap

It is the implementation of the Map interface backed by the hash table. It stores the key-value pairs. It does not allow null values. It is not synchronized. It never guarantees the insertion order. It provides constant time performance for methods like get, and put. Its performance depends on two factors — initial capacity and load factor. Capacity is the number of buckets in the hash table so the initial capacity is the number of buckets allocated at the time of creation. Load factor is the measure of how much a hash table can be populated before its capacity is increased. The rehash method is used to increase the capacity and it mainly doubles the number of buckets.

Example


import java.util.*;  
public class HashMapExample{  
    public static void main(String args[]){  
        //creating a HashMap
        HashMap<Integer,String> map=new HashMap<Integer,String>();    
        //putting elements into the map
        map.put(1,"England");    
        map.put(2,"USA");    
        map.put(3,"China");
        
        //get element at index 2
        System.out.println("Value at index 2 is: "+map.get(2));
        System.out.println("iterating map"); 
        //iterating the map 
        for(Map.Entry m : map.entrySet()){    
            System.out.println(m.getKey()+" "+m.getValue());    
        }   
    }  
}

Output

Value at index 2 is: China iterating map 1 England 2 USA 3 China
Collections in Java - 2

Algorithms

The Collections framework provides us with different algorithms for different operations to apply to the collections. Here we will look at which major operations are covered by these algorithms. It contains algorithms related to:
  1. Sorting
  2. Searching
  3. Shuffling
  4. Routine Data Manipulation
  5. Composition
  6. Finding Extreme Values
For better understanding we will discuss the sorting algorithm.

Sorting

The sort algorithm reorders a list according to an ordering relationship. Two forms of relationships are provided.
  1. Natural Ordering
  2. Comparison Ordering

Natural Ordering

In natural ordering a list is sorted according to its elements.

Comparison Ordering

In this form of ordering an additional parameter, which is a comparator, is passed along with the list. A slightly optimized merge sort algorithm is used for sorting which is fast and stable as it guarantees the n log(n) running time and it does not reorder equal elements. We will be using the same example from ArrayList to demonstrate the sorting.

Example


import java.util.*;  
public class SortingExample{  
    public static void main(String args[]){  
        //Creating arraylist
        ArrayList<String> books=new ArrayList<String>(); 
        //Adding a book to the arraylist
        books.add("A Time to Kill");
        //Adding a book to the arraylist
        books.add("Absalom, Absalom!");
        //Adding a book to the arraylist
        books.add("The House of Mirth");  
        //Adding a book to the arraylist
        books.add("East of Eden");
        //Traversing list through Iterator before sorting
        Iterator itrBeforeSort=books.iterator();  
        while(itrBeforeSort.hasNext()){  
            System.out.println(itrBeforeSort.next());  
        }
        //sorting the books
        Collections.sort(books);
        System.out.println("After sorting the books");
        //Traversing list through Iterator after sorting  
        Iterator itr=books.iterator();  
        while(itr.hasNext()){  
            System.out.println(itr.next());  
        }  
    }  
}

Output

A Time to Kill Absalom, Absalom! The House of Mirth East of Eden After sorting the books A Time to Kill Absalom, Absalom! East of Eden The House of Mirth

Conclusion

We hope by now you understand what is java collections framework, what are its interfaces and classes and how to implement its different classes. You can always use this framework to reduce your efforts in Java. Feel free to practice and get back here whenever you need more assistance. Happy learning!
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION