Collections: Java

List Interface

The List interface is a child of Collection Interface. The List interface is found in java.util package and inherits the Collection interface.

ArrayList

An ArrayList in Java is implemented as a resizable array, also known as a dynamic array. It provides an interface to work with a dynamically sized list of elements, allowing for efficient insertion, deletion, and random access.

import java.util.ArrayList;
import java.util.List;

public class ListObjectUsingArrayList {
    public static void main(String[] args) {
        // Initializing ArrayList with a specific initial capacity
        int n = 10;
        List<String> arrayList = new ArrayList<>(n);

        // Adding elements
        arrayList.add("Element 1");
        arrayList.add("Element 2");
        arrayList.add("Element 3");

        // Accessing elements
        String firstElement = arrayList.get(0);
        System.out.println("First Element: " + firstElement);

        // Updating elements
        arrayList.set(1, "Updated Element 2");

        // Removing first occurrence of given element
        arrayList.remove("Element 1");
        System.out.println(arrayList);

        // Remove element at index 1
        arrayList.remove(1);
        System.out.println(arrayList);

        // Checking if an element exists
        boolean containsElement = arrayList.contains("Element 2");
        System.out.println("Contains Element 2: " + containsElement);

        // Getting the size
        int size = arrayList.size();
        System.out.println("Size of ArrayList: " + size);

        // Iterating through elements
        for (String element : arrayList) {
            System.out.println(element);
        }

        // Checking if the ArrayList is empty
        boolean isEmpty = arrayList.isEmpty();
        System.out.println("Is ArrayList Empty: " + isEmpty);

        // Clearing all elements
        arrayList.clear();
        System.out.println("ArrayList after clearing: " + arrayList);
    }
}

Vector

A vector provides us with dynamic arrays in Java. Though, it may be slower than standard arrays but can be helpful in programs where lots of manipulation in the array is needed.

Let’s see how to create a List object using Vector class:

List<Integer> vector = new Vector<>(n);

Stack

Stack is a class that is implemented in the collection framework and extends the vector class models and implements the Stack data structure. The class is based on the basic principle of last-in-first-out.

Let’s see how to create a List object using Stack class:

List<Integer> stackObject = new Stack<Integer>();

LinkedList

LinkedList is a class that is implemented in the collection framework which inherently implements the linked list data structure.

It is a linear data structure where the elements are not stored in contiguous locations and every element is a separate object with a data part and address part.

Let’s see how to create a List object using LinkedList class:

List<Integer> ll = new LinkedList<Integer>();

Set Interface

The Set interface extends the Collection interface. It represents the unordered set of elements which doesn’t allow us to store the duplicate items.

HashSet

HashSet is one of the widely used classes which implements the Set interface.

import java.util.HashSet;
import java.util.Set;

public class HashSetOperations {
    public static void main(String[] args) {
        // Adding elements
        Set<String> hs = new HashSet<>();
        hs.add("B");
        hs.add("B");
        hs.add("C");
        hs.add("A");

        // Printing the elements inside the Set object
        System.out.println("HashSet after adding elements: " + hs);

        // Accessing elements
        System.out.println("Set is " + hs);

        String check = "D";
        System.out.println("Contains " + check + ": " + hs.contains(check));

        // Removing elements
        System.out.println("Initial HashSet: " + hs);
        hs.remove("B");
        System.out.println("After removing element 'B': " + hs);

        // Iterating through the Set
        System.out.print("Set elements: ");
        for (String value : hs) {
            System.out.print(value + ", ");
        }
        System.out.println();
    }
}

LinkedHashSet

LinkedHashSet class which is implemented in the collections framework is an ordered version of HashSet that maintains a doubly-linked List across all elements.

// Java program to demonstrate the 
// creation of Set object using 
// the LinkedHashset class 
import java.util.*; 
  
class LinkedHashSetClass { 
  
    public static void main(String[] args) 
    { 
        Set<String> lh = new LinkedHashSet<String>(); 
  
        // Adding elements into the LinkedHashSet 
        // using add() 
        lh.add("India"); 
        lh.add("Australia"); 
        lh.add("South Africa"); 
  
        // Adding the duplicate 
        // element 
        lh.add("India"); 
  
        // Displaying the LinkedHashSet 
        System.out.println(lh); 
  
        // Removing items from LinkedHashSet 
        // using remove() 
        lh.remove("Australia"); 
        System.out.println("Set after removing "
                           + "Australia:" + lh); 
  
        // Iterating over linked hash set items 
        System.out.println("Iterating over set:"); 
        Iterator<String> i = lh.iterator(); 
        while (i.hasNext()) 
            System.out.println(i.next()); 
    } 
}

Sorted Set Interface

The SortedSet interface present in java.util package extends the Set interface present in the collection framework. It is an interface that implements the mathematical set.

TreeSet

TreeSet class which is implemented in the collections framework and implementation of the SortedSet Interface and SortedSet extends Set Interface.

Let’s see how to create a Set object using TreeSet class:

Set<String> ts = new TreeSet<String>(); 

Map Interface

In Java, Map Interface is present in java.util package represents a mapping between a key and a value. Java Map interface is not a subtype of the Collection interface. Therefore it behaves a bit differently from the rest of the collection types.

HashMap

HashMap provides the basic implementation of the Map interface of Java. It stores the data in (Key, Value) pairs.

To access a value one must know its key.

// Java Program to illustrate the Hashmap Class 
  
// Importing required classes 
import java.util.*; 
  
// Main class 
public class MapObjectUsingHashMap { 
  
    // Main driver method 
    public static void main(String[] args) 
    { 
  
        // Creating an empty HashMap 
        Map<String, Integer> map = new HashMap<>(); 
  
        // Inserting entries in the Map 
        // using put() method 
        map.put("vishal", 10); 
        map.put("sachin", 30); 
        map.put("vaibhav", 20); 
  
        // Iterating over Map 
        for (Map.Entry<String, Integer> e : map.entrySet()) 
  
            // Printing key-value pairs 
            System.out.println(e.getKey() + " "
                               + e.getValue()); 
    } 
}

LinkedHashMap

LinkedHashMap is just like HashMap with the additional feature of maintaining an order of elements inserted into it.

Let’s see how to create a Map object using LinkedHashMap class:

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

TreeMap

The map is sorted according to the natural ordering of its keys, or by a Comparator provided at map creation time, depending on which constructor is used. This proves to be an efficient way of sorting and storing the key-value pairs.

Let’s see how to create a Map object using TreeMap class:

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

Queue Interface

The Queue interface is present in java.util package and extends the Collection interface is used to hold the elements about to be processed in FIFO(First In First Out) order.

LinkedList

import java.util.LinkedList;
import java.util.Queue;
 
public class QueueExample {
    public static void main(String[] args) {
        Queue<String> queue = new LinkedList<>();
 
        // add elements to the queue
        queue.add("apple");
        queue.add("banana");
        queue.add("cherry");
 
        // print the queue
        System.out.println("Queue: " + queue);
 
        // remove the element at the front of the queue
        String front = queue.remove();
        System.out.println("Removed element: " + front);
 
        // print the updated queue
        System.out.println("Queue after removal: " + queue);
 
        // add another element to the queue
        queue.add("date");
 
        // peek at the element at the front of the queue
        String peeked = queue.peek();
        System.out.println("Peeked element: " + peeked);
 
        // print the updated queue
        System.out.println("Queue after peek: " + queue);
    }
}

PriorityQueue

import java.util.*;

public class PriorityQueueOperations {
    public static void main(String[] args) {
        // Creating a PriorityQueue
        Queue<String> pq = new PriorityQueue<>();

        // Adding Elements
        pq.add("Geeks");
        pq.add("For");
        pq.add("Geeks");

        // Printing the PriorityQueue
        System.out.println("PriorityQueue after adding elements: " + pq);

        // Removing Elements
        System.out.println("Initial Queue: " + pq);
        pq.remove("Geeks");
        System.out.println("After Remove: " + pq);
        System.out.println("Poll Method: " + pq.poll()); // Removes and retrieves the head
        System.out.println("Final Queue: " + pq);

        // Iterating through the Queue using Iterator
        System.out.print("Iterating using Iterator: ");
        Iterator<String> iterator = pq.iterator();
        while (iterator.hasNext()) {
            System.out.print(iterator.next() + " ");
        }
        System.out.println();

        // Other operations:
        // Peek: Retrieves, but does not remove, the head of this queue
        System.out.println("Peek: " + pq.peek());

        // Size: Returns the number of elements in the queue
        System.out.println("Size of Queue: " + pq.size());

        // Contains: Checks if a specific element is present in the queue
        System.out.println("Contains 'For': " + pq.contains("For"));

        // Clear: Removes all elements from the queue
        pq.clear();
        System.out.println("Queue after clearing: " + pq);
    }
}

Deque Interface

Deque interface present in java.util package is a subtype of the queue interface. The Deque is related to the double-ended queue that supports the addition or removal of elements from either end of the data structure. It can either be used as a queue(first-in-first-out/FIFO) or as a stack(last-in-first-out/LIFO). Deque is the acronym for double-ended queue.

LinkedList

// Java program to demonstrate the working
// of a Deque in Java
 
import java.util.*;
 
public class DequeExample {
    public static void main(String[] args)
    {
        Deque<String> deque
            = new LinkedList<String>();
 
        // We can add elements to the queue
        // in various ways
 
        // Add at the last
        deque.add("Element 1 (Tail)");
 
        // Add at the first
        deque.addFirst("Element 2 (Head)");
 
        // Add at the last
        deque.addLast("Element 3 (Tail)");
 
        // Add at the first
        deque.push("Element 4 (Head)");
 
        // Add at the last
        deque.offer("Element 5 (Tail)");
 
        // Add at the first
        deque.offerFirst("Element 6 (Head)");
 
        System.out.println(deque + "\n");
 
        // We can remove the first element
        // or the last element.
        deque.removeFirst();
        deque.removeLast();
        System.out.println("Deque after removing "
                        + "first and last: "
                        + deque);
    }
}

ArrayDeque

import java.util.ArrayDeque;
import java.util.Deque;

public class ArrayDequeExample {
    public static void main(String[] args) {
        Deque<String> deque = new ArrayDeque<>();

        // Adding elements to the deque in various ways
        deque.add("Element 1 (Tail)");
        System.out.println(deque);

        deque.addFirst("Element 2 (Head)");
        System.out.println(deque);

        deque.addLast("Element 3 (Tail)");
        System.out.println(deque);

        deque.push("Element 4 (Head)");
        System.out.println(deque);

        deque.offer("Element 5 (Tail)");
        System.out.println(deque);

        deque.offerFirst("Element 6 (Head)");
        System.out.println(deque);

        // Removing elements from the deque
        deque.removeFirst();
        deque.removeLast();

        System.out.println("Deque after removing first and last: " + deque);

        // Other operations on ArrayDeque
        System.out.println("Peek First: " + deque.peekFirst());
        System.out.println("Peek Last: " + deque.peekLast());
        System.out.println("Poll First: " + deque.pollFirst());
        System.out.println("Poll Last: " + deque.pollLast());
        System.out.println("Size of Deque: " + deque.size());
        System.out.println("Contains 'Element 3 (Tail)': " + deque.contains("Element 3 (Tail)"));

        // Clearing all elements
        deque.clear();
        System.out.println("Deque after clearing: " + deque);
    }
}

Comparables

The Comparable interface in Java is essential for defining a natural ordering for a class. By implementing Comparable, a class provides a standardized way to compare instances of that class. This natural ordering is particularly useful for sorting elements in collections like TreeSet or when utilizing sorting algorithms such as Collections.sort().

The Comparable interface contains a single method:

int compareTo(T other)

Here, T represents the type of objects being compared. The compareTo method returns a negative integer, zero, or a positive integer based on whether the current object is less than, equal to, or greater than the object being compared.

For example, consider a Person class that implements the Comparable interface to define a natural ordering based on age:

import java.util.*;

class Person implements Comparable<Person> {
    
    String name;
    int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
     }

    @Override
     public int compareTo(Person other) {
         return Integer.compare(this.age, other.age);
    }
    
}

Comparators

In Java, the Comparator interface provides a means to define custom ordering for objects in collections. It is particularly useful when sorting objects in a way that deviates from their natural order or when working with classes that don't implement Comparable.

Here's a simple example of how you might use a Comparator to sort a list of Person objects based on their ages:

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

class Person {
    
    String name;
    int age;
    
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

class AgeComparator implements Comparator<Person> {

    @Override
    public int compare(Person person1, Person person2) {
        return Integer.compare(person1.age, person2.age);
    }
}

public class ComparatorExample {
    
    public static void main(String[] args) {

        List<Person> people = new ArrayList<>();
        
        people.add(new Person("Alice", 28));
        people.add(new Person("Bob", 22));
        people.add(new Person("Charlie", 25));
        
        // Sort the list using the AgeComparator
        Collections.sort(people, new AgeComparator());
        
        // Iterate the List of people and check if it is now sorted on the basis of age or not.
        for (Person person : people) {
            System.out.println(person.name + " - " + person.age);
        }
    }
}