Collections In Java

In Java, the Collection framework offers a structure for storing and managing a set of objects.

Java Collections offer a comprehensive set of functionalities for managing data, including searching, sorting, inserting, modifying, and removing elements.

In Java, a Collection represents a cohesive group of objects. The Java Collection framework offers numerous interfaces (like Set, List, Queue, Deque) and classes (such as ArrayList, Vector, LinkedList, PriorityQueue, HashSet, LinkedHashSet, TreeSet).

What is Collection?

A Collection is a cohesive entity that encapsulates a set of objects.

What is a framework?

A framework provides a ready-made structure of classes and interfaces for building software applications efficiently. It simplifies adding new features by offering reusable components that perform similar tasks, eliminating the need to create a framework from scratch for each new project. This approach enhances object-oriented design, making development quicker, more consistent, and reliable.

  • It provides readymade architecture.
  • It represents a set of classes and interfaces.
  • It is optional.
  • What is the Collection Framework?

The Collection framework serves as a cohesive structure for managing and handling a set of items. It improves the effectiveness and clarity of code by providing a range of data arrangements like arrays, linked lists, trees, and hash tables, customized to meet diverse programming requirements. Key components include:

  • Interfaces along with their corresponding implementations in classes
  • Algorithms
  • Why Collection Framework?

Prior to the introduction of the Collection Framework in JDK 1.2, Java utilized Arrays, Vectors, and Hash tables for collections without a unified interface. This resulted in each collection type having its unique methods, syntax, and constructors, lacking standardization or consistency across them.

This complexity posed challenges for users in recalling the various capabilities of each type of collection, impacting the consistency and reusability of code. The varied characteristics of these collections underscored the necessity for a cohesive Collection Framework in Java to streamline and establish uniformity in collection operations.

Advantages of the Java Collection Framework

The Java Collections Framework offers significant advantages that enhance development practices, code quality, and application performance:

  • Reusability: The framework provides a comprehensive set of common classes and utility methods applicable across various types of collections. This feature promotes code reusability, sparing developers the need to write duplicate code for common operations.
  • Quality: Leveraging the Java Collections Framework elevates the quality of programs. The components within the framework have been extensively tested and are widely used by a vast community of developers, ensuring reliability and stability in your applications.
  • Speed: Developers often report an increase in development speed when using the Collections Framework. It allows them to concentrate on the core business logic of their applications rather than on implementing generic collection functionalities, thus speeding up the development process.
  • Maintenance: The open-source nature of the Java Collections Framework, coupled with readily available API documentation, facilitates easier code maintenance. Code written using the framework can be easily understood and taken over by other developers, ensuring continuity and ease of maintenance.
  • Reduces Effort to Design New APIs: An additional benefit is the reduced necessity for API designers and implementers to create new collection mechanisms for each new API. They can instead rely on the standard collection interfaces provided by the framework, streamlining the API development process and ensuring consistency across Java applications.
  • Hierarchy of Collection Framework

Let's examine the structure of the Collection framework. Within the java.util package, you can find a comprehensive set of classes and interfaces that form the Collection framework.

The Java Collections Framework revolves around essential interfaces such as Collection, List, Set, Queue, and Map, each designed for distinct data management purposes. Classes like ArrayList, HashSet, and HashMap provide effective approaches to managing these collections, equipping Java programmers with a diverse array of resources for effective data manipulation.

  • Class: In programming, a class serves as a template for creating objects. It holds the characteristics of objects using fields (attributes) and specifies actions through methods. Classes enable inheritance, allowing one class to inherit properties and methods from another class, which promotes code reusability and polymorphism.
  • Interface: An interface in Java is a type that can include constants and abstract methods (methods without implementation). It outlines the actions a class needs to perform without detailing how these actions are carried out, mandating the implementation of specific methods by the class. Interfaces are vital for achieving abstraction and supporting multiple inheritance in Java.
  • Methods of Collection interface

Numerous techniques are specified within the Collection interface. In Java, the Collection interface offers fundamental functions for managing sets of items, like inserting, deleting, and traversing every item. The methods included are:

Method Description
public boolean add(E e) It is used to insert an element in this collection.
public boolean addAll(Collection<? extends E> c) It is used to insert the specified collection elements in the invoking collection.
public boolean remove(Object element) It is used to delete an element from the collection.
public boolean removeAll(Collection<?> c) It is used to delete all the elements of the specified collection from the invoking collection.
default boolean removeIf(Predicate<? super E> filter) It is used to delete all the elements of the collection that satisfy the specified predicate.
public boolean retainAll(Collection<?> c) It is used to delete all the elements of the invoking collection except the specified collection.
public int size() It returns the total number of elements in the collection.
public void clear() It removes the total number of elements from the collection.
public boolean contains(Object element) It is used to search for an element.
public boolean containsAll(Collection<?> c) It is used to search the specified collection in the collection.
public Iterator iterator() It returns an iterator.
public Object[] toArray() It converts the collection into an array.
public <T> T[] toArray(T[] a) It converts the collection into an array. Here, the runtime type of the returned array is that of the specified array.
public boolean isEmpty() It checks if the collection is empty.
default Stream<E> parallelStream() It returns a possibly parallel Stream with the collection as its source.
default Stream<E> stream() It returns a sequential Stream with the collection as its source.
default Spliterator<E> spliterator() It generates a Spliterator over the specified elements in the collection
public boolean equals(Object element) It matches two collections.
public int hashCode() It returns the hash code number of the collection.

Iterator Interface

The iterator interface allows for the iteration of elements exclusively in a forward direction.

Methods of Iterator Interface

The Iterator interface comprises a total of three methods, which include:

Method Description
public boolean hasNext() It returns true if the iterator has more elements; otherwise, it returns false.
public Object next() It returns the element and moves the cursor pointer to the next element.
public void remove() It removes the last elements returned by the iterator. It is less used.

Iterable Interface

The Iterable interface serves as the foundational interface for all collection classes. By extending the Iterable interface, the Collection interface ensures that all its derived classes automatically adhere to the Iterable interface as well.

It contains only one abstract method. i.e.,

Example

Iterator<T> iterator()

The function provides an iterator that traverses through elements of type T.

Collection Interface

The Collection interface serves as the blueprint implemented by all classes within the collection framework. It defines the essential methods that every collection must possess. Essentially, the Collection interface establishes the fundamental structure that the collection framework relies upon.

The Collection interface includes various methods like adding an object with the Boolean add(Object obj) method, adding all elements from another collection with Boolean addAll(Collection c), and clearing all elements with void clear. These methods are universally implemented by all subclasses of the Collection interface.

To read more: Java Collection Interface

List Interface

The List interface is a sub-interface of the Collection interface. It represents a data structure that stores objects in a specific order and allows duplicate values. Various classes such as ArrayList, LinkedList, Vector, and Stack implement the List interface. When creating an instance of the List interface, we should use:

Example

List <data-type> list1= new ArrayList();

List <data-type> list2 = new LinkedList();

List <data-type> list3 = new Vector();

List <data-type> list4 = new Stack();

Various methods in List interface can be used to insert, delete, and access the elements from the list. The classes that implement the List interface are given below:

  • ArrayList
  • LinkedList
  • Vector
  • Stack

To read more: Java List Interface

ArrayList

The List interface is implemented by the ArrayList class, which utilizes a dynamic array to hold elements of various data types. The ArrayList class preserves the order of insertion and is not synchronized. Elements in the ArrayList can be accessed randomly. Take a look at the example below.

To read more: Java ArrayList

Example of ArrayList

Example

Example

import java.util.*;  

public class Main {  

    public static void main(String args[]) {  

            ArrayList<String> list=new ArrayList<String>();//Creating arraylist  

            list.add("John");//Adding object in arraylist  

            list.add("Peter");  

            list.add("Lucy");  

            list.add("Johnson");  

            //Traversing list through Iterator  

            Iterator itr=list.iterator();  

            while(itr.hasNext()) {  

            System.out.println(itr.next());  

        }  

    }  

}

Output:

Output

John

Peter

Lucy

Johnson

LinkedList

The Collection interface is implemented by LinkedList, which internally utilizes a doubly linked list to hold elements. This data structure allows for the storage of duplicate elements while preserving their insertion order. It is important to note that LinkedList is not synchronized. One of the key advantages of using LinkedList is its efficient manipulation process, as it does not necessitate any shifting of elements. Let's explore the practical application of LinkedList with the following example.

To read more: Java LinkedList

Example of LinkedList

Example

Example

import java.util.*;  

public class Main {  

    public static void main(String args[]) {  

        LinkedList<String> al=new LinkedList<String>();  

        al.add("Lucy");  

        al.add("Peter");  

        al.add("Lucy");  

        al.add("John");  

        Iterator<String> itr=al.iterator();  

        while(itr.hasNext()) {  

            System.out.println(itr.next());  

        }  

    }  

}

Output:

Output

Lucy

Peter

Lucy

John

Vector

A Vector utilizes a resizable array to hold its data elements, resembling an ArrayList. Nevertheless, it is synchronized and includes various methods that are distinct from the Collection framework. Take into account the subsequent illustration.

To read more: Java Vector

Example

Example

import java.util.*;  

    public class Main {  

        public static void main(String args[]) {  

        Vector<String> v=new Vector<String>();  

        v.add("Apple");  

        v.add("Banana");  

        v.add("Orange");  

        v.add("Plum");  

        Iterator<String> itr=v.iterator();  

        while(itr.hasNext()){  

            System.out.println(itr.next());  

        }  

    }  

}

Output:

Output

Apple

Banana

Orange

Plum

Stack

The stack is a derived class of Vector, serving as an implementation of the last-in-first-out data structure known as a Stack. It inherits all functionalities from the Vector class and introduces its own methods including push, peek, and push(object o) to enhance its characteristics. An illustration of its usage is presented below.

To read more: Java Stack class

Example

Example

import java.util.*;  

    public class Main {  

        public static void main(String args[]) {  

        Stack<String> stack = new Stack<String>();  

        stack.push("CPU");  

        stack.push("Monitor");  

        stack.push("Mouse");  

        stack.push("Keyboard");  

        stack.push("Printer");

        stack.pop();  

        Iterator<String> itr=stack.iterator();  

        while(itr.hasNext()) {  

            System.out.println(itr.next());  

        }  

    }  

}

Output:

Output

CPU

Monitor

Mouse

Keyboard

Queue Interface

The queue interface follows a first-in-first-out order, functioning as an ordered collection for storing elements awaiting processing. Different classes such as PriorityQueue, Deque, and ArrayDeque are examples of implementations of the Queue interface.

Queue interface can be instantiated as:

Example

Queue<String> q1 = new PriorityQueue();

Queue<String> q2 = new ArrayDeque();

Various classes implement the Queue interface; some of them are given below:

  • PriorityQueue
  • Deque
  • ArrayDeque
  • PriorityQueue

The Queue interface is implemented by the PriorityQueue class to manage elements or objects based on their priorities. Null values are not permitted to be stored within a PriorityQueue. Let's examine the provided example.

To read more: Java Stack class

Example of PriorityQueue

Example

Example

import java.util.*;  

public class Main {  

    public static void main(String args[]) {  

        PriorityQueue<String> queue=new PriorityQueue<String>();  

        queue.add("Alice");  

        queue.add("Daniel");  

        queue.add("Jones");  

        queue.add("Smith");  

        System.out.println("head:"+queue.element());  

        System.out.println("head:"+queue.peek());  

        System.out.println("iterating the queue elements:");  

        Iterator itr=queue.iterator();  

        while(itr.hasNext()) {  

            System.out.println(itr.next());  

        }  

        queue.remove();  

        queue.poll();  

        System.out.println("after removing two elements:");  

        Iterator<String> itr2=queue.iterator();  

        while(itr2.hasNext()) {  

            System.out.println(itr2.next());  

        }  

    }  

}

Output:

Output

head:Alice

head:Alice

iterating the queue elements:

Alice

Daniel

Jones

Smith

after removing two elements:

Jones

Smith

Deque Interface

The Deque interface is an extension of the Queue interface, allowing for the addition and removal of elements from both ends. Deque, short for double-ended queue, facilitates operations on both the front and back ends.

Deque can be instantiated as:

Example

Deque d = new ArrayDeque();

ArrayDeque

The ArrayDeque class is an implementation of the Deque interface, providing functionality for using double-ended queues. Unlike a regular queue, it allows for adding or removing elements from both the front and the back. ArrayDeque outperforms ArrayList and Stack in speed and does not have any limitations on capacity. Let's explore the usage of ArrayDeque with the example below.

To read more: Java Deque Interface

Example of ArrayDeque

Example

Example

import java.util.*;  

public class Main{  

    public static void main(String[] args) {  

        //Creating Deque and adding elements  

        Deque<String> deque = new ArrayDeque<String>();  

        deque.add("Lucy");  

        deque.add("Andrew");  

        deque.add("Henery"); 

        //Traversing elements  

        for (String str : deque) {  

            System.out.println(str);  

        }  

    }  

}

Output:

Output

Lucy

Andrew

Henery

Set Interface

The Set Interface is part of the java.util package in Java. It is an extension of the Collection interface and is used to manage a collection of elements without allowing duplicates. Within a Set, only one null value can be stored at most. HashSet, LinkedHashSet, and TreeSet are implementations of the set interface. To create an instance of a set, it can be instantiated as follows:

Example

Set<data-type> s1 = new HashSet<data-type>();

Set<data-type> s2 = new LinkedHashSet<data-type>();

Set<data-type> s3 = new TreeSet<data-type>();

HashSet

The Set Interface is implemented by the HashSet class, which is used to store a collection using a hash table. Hashing is employed to store elements within the HashSet, ensuring uniqueness of items. An example illustrating this concept is provided below.

To read more: Java HashSet

Example

Example

import java.util.*;  

public class Main  {  

    public static void main(String args[]) {  

        //Creating HashSet and adding elements  

        HashSet<String> set=new HashSet<String>();  

        set.add("Andrew");  

        set.add("Mark");  

        set.add("Peter");  

        set.add("Johnson");

        //Traversing elements  

        Iterator<String> itr=set.iterator();  

        while(itr.hasNext()) {  

            System.out.println(itr.next());  

        }  

    }  

}

Output:

Output

Johnson

Andrew

Mark

Peter

LinkedHashSet

The LinkedHashSet class is a LinkedList-based implementation of the Set Interface, extending the HashSet class and implementing the Set interface. Similar to HashSet, it stores distinct elements, preserves the order of insertion, and allows for null elements. Below is an illustration to demonstrate this.

To read more: Java LinkedHashSet Class

Example

Example

import java.util.*;  

public class Main{  

    public static void main(String args[]){  

        LinkedHashSet<String> set=new LinkedHashSet<String>();  

        set.add("Peter");  

        set.add("Jack");  

       set.add("Peter");  

      set.add("Johnson"); 

        Iterator<String> itr=set.iterator();  

        while(itr.hasNext()){  

            System.out.println(itr.next());  

        }  

    }  

}

Output:

Output

Peter

Jack

Johnson

SortedSet Interface

SortedSet serves as a substitute for the Set interface by offering a complete arrangement of its elements. Its elements are organized in ascending order. Additionally, the SortedSet offers extra methods that prevent the default ordering of the elements.

The SortedSet can be instantiated as:

Example

SortedSet<data-type> set = new TreeSet();

To read more: Java SortedSet Interface

TreeSet

The Java TreeSet class is an implementation of the Set interface that utilizes a tree structure for storage. Similar to HashSet, TreeSet ensures that all elements within it are unique. Notably, TreeSet offers efficient access and retrieval times. Elements within a TreeSet are organized and stored in ascending order. Let's explore this through the following illustration.

To read more: Java TreeSet Class

Example

Example

import java.util.*;  

public class Main{  

    public static void main(String args[]){  

        //Creating and adding elements  

        TreeSet<String> set=new TreeSet<String>();  

       set.add("Thomas");  

        set.add("Davis");  

        set.add("Thomas");  

        set.add("Donald"); 

        //traversing elements  

        Iterator<String> itr=set.iterator();  

        while(itr.hasNext()){  

            System.out.println(itr.next());  

        }  

    }  

}

Output:

Output

Davis

Donald

Thomas

Map Interface

The Java Collections Framework includes the Map interface, which is designed to establish a relationship between a group of keys and their associated values. Each key within a Map must be unique and can have only one corresponding value. This interface facilitates the storage of key-value pairs and offers a convenient method for accessing, modifying, and managing data by using keys as references.

Syntax:

Example

Map<T, T> hm = new HashMap<>(); 

Map<T, T> tm = new TreeMap<>();

To read more: Java Map Interface

HashMap

In Java, a HashMap is a data structure that stores key-value pairs efficiently by utilizing hashing for quick access to data based on keys. Hashing involves transforming large data like strings or objects into smaller, uniform values to facilitate rapid indexing and searching operations. HashMap in Java adheres to the Map interface and proves to be beneficial for handling extensive datasets effectively. Moreover, HashSet leverages HashMap internally to ensure unique element storage, highlighting the effectiveness of hashing within Java's collections framework for speedy data retrieval and organization.

To read more: Java HashMap

Example

Example

import java.util.HashMap;

import java.util.Map;

public class Main {

    public static void main(String[] args) {

        // Creating a HashMap

        Map<String, Integer> map = new HashMap<>();

        // Adding key-value pairs to the HashMap

        map.put("Alice", 10);

        map.put("Bob", 20);

        map.put("Charlie", 30);

        // Retrieving a value

        System.out.println("Value for 'Alice': " + map.get("Alice"));

        // Iterating over key-value pairs

        for (Map.Entry<String, Integer> entry : map.entrySet()) {

            String key = entry.getKey();

            Integer value = entry.getValue();

            System.out.println(key + ": " + value);

        }

        // Removing a key-value pair

        map.remove("Charlie");

        // Checking the presence of a key

        if (map.containsKey("Bob")) {

            System.out.println("Map contains key 'Bob'.");

        }

    }

}

Output:

Output

Value for 'Alice': 10Bob: 20

Alice: 10

Charlie: 30

Map contains key 'Bob'.

Java Collections MCQ

  1. Which method would you use to insert an element at a specific position in a List?
  • add
  • addAt
  • insert
  • addElement

Explanation: The add(int index, E element) method is used to insert an element at a specific position in a List.

  1. What is the time complexity of the contains method in a HashSet?
  • O(1)
  • O(log n)
  • O(n)
  • O(n^2)

Explanation: Due to its underlying hash table structure, the contains method in a HashSet has a time complexity of O(1).

  1. What is the primary difference between a HashMap and a TreeMap?
  • HashMap is synchronized, TreeMap is not
  • HashMap maintains the order of elements, TreeMap does not
  • HashMap allows null keys, TreeMap does not
  • TreeMap sorts the keys, HashMap does not

Explanation: TreeMap sorts the keys in natural order or by a specified comparator, while HashMap does not maintain any order.

  1. Which interface does LinkedHashSet implement in addition to Set?
  • List
  • SortedSet
  • Collection

Explanation: LinkedHashSet implements the Set interface, which extends Collection.

  1. What happens if you try to add a duplicate element to a TreeSet?
  • The duplicate element is added
  • The existing element is replaced
  • The TreeSet throws an exception
  • The duplicate element is ignored

In a TreeSet data structure, duplicate elements are disregarded and not included in the set.

Input Required

This code uses input(). Please provide values below: