Java Collections Interview Questions
Published on

Java Collections Interview Questions

Authors

In this post, I will be list out the questions and answers for the most common interview questions for Java Collections. We must know the basics of ArrayList, LinkedList, and other collections like HashMap, TreeMap, LinkedHashMap, etc. Also, one must prepare for questions being asked on Concurrent Collections, i.e., HashTable, ConcurrentHashMap, etc.

Table of Contents

Explain Java ArrayList?

The difference between a built-in array and an ArrayList in Java is that the size of an array cannot be modified. While elements can be added and removed from an ArrayList whenever needed.

Implementation of ArrayList is not synchronized by default. It means if a thread modifies it structurally and multiple threads access it concurrently, it must be synchronized externally.

import java.util.ArrayList;
public class Main {
  public static void main(String[] args) {
    ArrayList<String> cars = new ArrayList<String>();
    cars.add("Volvo");
    cars.add("BMW");
    cars.add("Ford");
    cars.add("Mazda");
    System.out.println(cars);
  }
}

Explain Java Vector?

Vector is like the dynamic array which can grow or shrink its size. It is a part of the Java Collection framework since Java 1.2.

It is recommended to use the Vector class in the thread-safe implementation only. If you don’t need to use the thread-safe implementation, you should use the ArrayList.

import java.util.*;
public class Main {
       public static void main(String args[]) {
          //Create a vector
          Vector<String> vec = new Vector<String>();
          //Adding elements using add() method of List
          vec.add("Tiger");
          vec.add("Lion");
          vec.add("Dog");
          vec.add("Elephant");
          //Adding elements using addElement() method of Vector
          vec.addElement("Rat");
          vec.addElement("Cat");
          vec.addElement("Deer");

          System.out.println("Elements are: "+vec);
       }
}

Explain Java Iterator?

An Iterator is an object that can be used to loop through collections, like ArrayList and HashSet. It supports only looping through in forward direction.

To use an Iterator, you must import it from java.util package.

Iterators are designed to change the collections that they loop through easily. The remove() method can remove items from a collection while looping.

// Import the ArrayList class and the Iterator class
import java.util.ArrayList;
import java.util.Iterator;
public class Main {
  public static void main(String[] args) {
    // Make a collection
    ArrayList < String > cars = new ArrayList < String > ();
    cars.add("Volvo");
    cars.add("BMW");
    cars.add("Ford");
    cars.add("Mazda");
    // Get the iterator
    Iterator < String > it = cars.iterator();
    // Print the first item
    System.out.println(it.next());
    // Print from second item, but skip BMW
    while (it.hasNext()) {
      String car = it.next();
      if (car == "BMW") {
        it.remove();
        continue;
      }
      System.out.println(car);
    }
  }
}

Explain Java ListIterator?

ListIterator extends Iterator, It is useful only for List implemented classes. Unlike an iterator, ListIterator can move in both directions forward and backward. It is a Bi-directional Iterator.

Forward Direction

  1. hasNext()
  2. next()
  3. nextIndex()

Backward Direction

  1. hasPrevious()
  2. previous()
  3. previousIndex()

It supports CRUD operations: CREATE, READ, UPDATE and DELETE operations. It does NOT support Parallel iteration of elements.

Valid for the following collections:

  1. java.util.ArrayList
  2. java.util.LinkedList
  3. java.util.Vector
  4. java.util.Stack
import java.util.*;

public class ListIteratorExample
{
	public static void main(String[] args)
	{
		List<String> names = new LinkedList<>();
		names.add("Rahul");
		names.add("CodingJump");
		names.add("Suresh");

		// Getting ListIterator
		ListIterator<String> listIterator = names.listIterator();

		// Traversing elements
		System.out.println("Forward Direction Iteration:");
		while(listIterator.hasNext()){
			System.out.println(listIterator.next());
		}

		// Traversing elements, the iterator is at the end at this point
		System.out.println("Backward Direction Iteration:");
		while(listIterator.hasPrevious()){
			System.out.println(listIterator.previous());
		}
	}
}

Explain about Java Enumeration Interface?

This legacy interface has been superseded by Iterator, although not deprecated. It is used for Legacy collections like Vector, Stack, HashTable, etc.

Useful points about Java Enumeration Interface

  1. Supports iteration in forward direction only.
  2. For new collections/code, Enumeration is considered obsolete.
  3. Enumeration is Synchronized.
  4. It does not support adding, removing, or replacing elements.
  5. ArrayEnumeration which implements java.util.Enumeration is deprecated.

Methods

  1. hasMoreElements()
  2. nextElement()
// Java program to test Enumeration
import java.util.Vector;
import java.util.Enumeration;

public class EnumerationExample {

    public static void main(String args[])
    {
        Enumeration months;
        Vector<String> monthNames = new Vector<>();

        monthNames.add("January");
        monthNames.add("Febraury");
        monthNames.add("March");
        monthNames.add("April");
        monthNames.add("May");
        monthNames.add("June");
        monthNames.add("July");
        monthNames.add("August");
        monthNames.add("September");
        monthNames.add("Octobor");
        monthNames.add("November");
        monthNames.add("December");
        months = monthNames.elements();

        while (months.hasMoreElements()) {
            System.out.println(months.nextElement());
        }
    }
}

Explain about Java BlockingQueue?

BlockingQueue is an interface used in Java that can extends Queue. It provides concurrency in various queue operations like retrieval, insertion, deletion, etc.

For instance, if a thread tries to take an element and there are none left in the queue, the thread can be blocked until there is an element to take. Whether or not the calling thread is blocked depends on what methods you call on the BlockingQueue.

Since BlockingQueue is an interface, you need to use one of its implementations to use it. The java.util.concurrent package has the following implementations of the BlockingQueue interface:

  1. ArrayBlockingQueue
  2. DelayQueue
  3. LinkedBlockingQueue
  4. LinkedBlockingDeque
  5. LinkedTransferQueue
  6. PriorityBlockingQueue
  7. SynchronousQueue

BlockingQueue makes it easy to implement producer-consumer design pattern by providing inbuilt blocking support for the put() and take() method

Throws ExceptionSpecial ValueBlocksTimes Out
Insertadd(o)offer(o)put(o)offer(o, timeout, timeunit)
Removeremove(o)poll()take()poll(timeout, timeunit)
Examineelement()peek()

Throws Exception:

If the attempted operation is not possible immediately, an exception is thrown.

Special Value:

If the attempted operation is not possible immediately, a special value is returned (often true/false).

Blocks:

If the attempted operation is not possible immediately, the method call blocks until it is.

Times Out:

Suppose the attempted operation is not possible immediately; the method call blocks until it is but waits no longer than the given timeout. Returns a special value telling whether the operation succeeded or not (typically true/false).

import java.util.concurrent. * ;
import java.util. * ;
public class BlockingQueueExample {
	public static void main(String[] args)
	throws InterruptedException {
		int capacity = 10;
		// create object of ArrayBlockingQueue
		BlockingQueue < String > queue = new ArrayBlockingQueue < String > (capacity);
		// Add elements
		queue.put("StarWars");
		queue.put("SuperMan");
		queue.put("Flash");
		queue.put("BatMan");
		queue.put("Avengers");
		System.out.println("queue contains " + queue);
		// remove some elements
		queue.remove();
		queue.remove();
		queue.put("CaptainAmerica");
		queue.put("Thor");
		System.out.println("queue contains " + queue);
	}
}

Explain Java Queue?

Java Queue is an interface available in java.util package and extends java.util.Collection interface

Java Queue follows FIFO order to insert and remove its elements. FIFO stands for First In First Out.

OperationThrows ExceptionSpecial value
Insertadd(e)offer(e)
Removeremove(e)poll()
Examineelement()peek()

The most frequently used Queue implementations are:

  1. LinkedList
  2. ArrayBlockingQueue
  3. PriorityQueue
import java.util.*;
public class QueueExample {
   public static void main(String[] args) {

	Queue<String> queue = new LinkedList<>();
	queue.add("one");
	queue.add("two");
	queue.add("three");
	queue.add("four");
	System.out.println(queue);

	queue.remove("three");
	System.out.println(queue);
	System.out.println("Queue Size: " + queue.size());
	System.out.println("Queue contains three? " + queue.contains("three"));
	// To empty the queue
	queue.clear();
   }
}

What is Java Stack Collection?

Stack also implements interfaces List, Collection, Iterable, Cloneable, Serializable. It follows the Last In First Out (LIFO) process.

import java.util.Stack;
public class StackExample {
	public static void main(String[] args) {
		Stack < Integer > stack = new Stack < >();
		boolean result = stack.empty();
		System.out.println("Is the stack empty? " + result);
		// pushing elements into stack
		stack.push(1);
		stack.push(2);
		stack.push(3);
		stack.push(4);
		System.out.println("Elements in Stack: " + stack);
		result = stack.empty();
		System.out.println("Is the stack empty? " + result);
	}
}

Explain Java HashMap?

HashMap is a part of the Java collection framework. It uses a technique called Hashing and implements the map interface. It stores the data in the pair of Key and Value.

equals() and hashCode() both are very important methods needed for the functioning of HashMap.

The default size of HashMap is 16, the capacity is increased to 2^5=32, 2^6=64, and so on.

The default load factor of HashMap=0.75, so after 12 elements, the size of the HashMap doubles. Both the initial capacity and load factor can be changed as per user needs.

Every time the size changes, there is a lot of work that needs to be done in the background to keep the consistency, like moving relevant elements to different buckets, etc. So it’s better to estimate the size beforehand, even if not exactly accurate.

We’ll also need to discuss buckets in HashMap; if there is a clash in the index calculated based on the hashCode() and size of HashMap, the items with the same index will get added to LinkedList, which is called a bucket. If the items in the bucket are more than TREEIFY_THRESHOLD (8 default value), then the linked list gets converted into a perfectly balanced red-black tree to reduce the time complexity from O(N) to O(log N).

Index is calculated as hashCode() & (N-1)

One more point to note is that HashMap allows you to insert the same key multiple times, if you’ve changed the value, it will update the value accordingly, so when you’re using HashMap on custom-defined classes, make sure to override the equals() and hashCode() keeping this in mind.

import java.util.*;
public class HashMapExample {
    public static void main(String args[])
    {
        HashMap<Integer, String> hm = new HashMap<Integer, String>();
        hm.put(1, "CodingJump");
        hm.put(2, "Rahul");
        hm.put(3, "Neelakantan");
        System.out.println("Values " + hm);
        System.out.println("3: "+ hm.get(3));
    }
}

Explain Java Comparable Interface?

Java Comparable interface is used to order the objects of the user-defined class. All default collections sort the elements like Collections.Sort(), TreeMap, etc., use compareTo method.

// It is used to compare the current object with the specified object
public int compareTo(Object obj)

Positive integer: if the current object is greater than the specified object.
Negative integer: if the current object is less than the specified object.
Zero: if the current object is equal to the specified object.

import java.util. * ;
class Student implements Comparable < Student > {
	String name;
	int age;
	Student(String name, int age) {
		this.name = name;
		this.age = age;
	}
	public int compareTo(Student st) {
		if (age == st.age) return 0;
		else if (age > st.age) return 1;
		else return - 1;
	}
}
public class SortExample {
	public static void main(String args[]) {
		ArrayList < Student > al = new ArrayList < Student > ();
		al.add(new Student("CodingJump", 23));
		al.add(new Student("Rahul", 27));
		al.add(new Student("Neelakantan", 21));
		Collections.sort(al);
		for (Student st: al) {
			System.out.println(st.name + " " + st.age);
		}
	}
}

Explain Comparator Interface in Java?

A comparator interface is used to order the objects of user-defined classes.

The main difference between Comparator & Comparable is that Comparator should be defined in a different class, not in the user-defined class. In contrast, Comparable, we have to implement it inside the user-defined class.

public int compare(Object obj1, Object obj2)
import java.io. * ;
import java.lang. * ;
import java.util. * ;
class Student {
	int rollno;
	String name,
	address;
	public Student(int rollno, String name, String address) {
		this.rollno = rollno;
		this.name = name;
		this.address = address;
	}
}
class Sortbyroll implements Comparator < Student > {
	public int compare(Student a, Student b) {
		return a.rollno - b.rollno;
	}
}
public class Main {
	public static void main(String[] args) {
		ArrayList < Student > ar = new ArrayList < Student > ();
		ar.add(new Student(100, "CodingJump", "India"));
		ar.add(new Student(300, "Rahul", "India"));
		ar.add(new Student(200, "Neelakantan", "USA"));
		Collections.sort(ar, new Sortbyroll());
		System.out.println("\nSorted by rollno");
		for (int i = 0; i < ar.size(); i++)
		System.out.println(ar.get(i).name);
	}
}

Explain about Java TreeMap?

Java TreeMap class is a red-black tree-based implementation. It provides an efficient means of storing key-value pairs in sorted order.

TreeMap uses compareTo() function rather than hashCode() and equals() methods.

However, it is a good practice to override them properly, should you use this object as a key for HashMap (for example) in the future.

Useful properties

  • Java TreeMap is non synchronized.
  • It maintains ascending order.
  • Java TreeMap contains only unique elements.
  • Java TreeMap cannot have a null key but can have multiple null values.
/static/images/posts/2021/java-collections-interview-questions/tree-map-hierarchy.png
import java.util.*;
class TreeMapExample {
 public static void main(String args[]){
   TreeMap<Integer,String> map=new TreeMap<Integer,String>();
      map.put(100,"CodingJump");
      map.put(102,"Rahul");
      map.put(101,"Neelakantan");
      for(Map.Entry m:map.entrySet()){
       System.out.println(m.getKey()+" "+m.getValue());
      }
 }

Explain HashTable in Java?

HashTable is an ancient class, which is a synchronized collection. It is similar to HashMap, but it doesn’t allow null, whereas HashMap does. To successfully store and retrieve objects from a HashTable, the objects used as keys must implement the hashCode method and the equals method. Since null is not an object, it can’t implement these methods. HashMap is an advanced version and improvement on the Hashtable. HashMap was created later.

But later on, it was realized that null key and value have their importance, then they revised implementations of HashTable were introduced like HashMap, which allows one null key and multiple null values.

For HashMap, it allows one null key, and there is a null check for keys; if the key is null, then that element will be stored in a zero location in the Entry array.

Modified and better implementation of HashTable was later introduced as ConcurrentHashMap.

List out benefits of generic collection?

  1. If the programmers are using generic classes, they don’t require typecasting.
  2. It is type-safe and can be checked at the time of compilation.
  3. It provides the stability of the code by detecting bugs at the compilation time.

What is the difference between Set and Map?

Set stores unique values in a collection, and the Set interface does not maintain insertion order. Whereas Map is a collection of key-value pairs, this also doesn’t preserve insertion order.

We can use LinkedHashSet or LinkedHashMap to maintain insertion order.

What is the difference between HashSet and LinkedHashSet?

HashSet is an unordered & unsorted collection of the data set, whereas LinkedHashSet is an ordered collection of HashSet. HashSet does not provide any method to maintain the insertion order. Comparatively, LinkedHashSet maintains the insertion order of the elements.

How do we create a sorted HashSet of user-defined class objects?

We can use TreeSet for this purpose; if we want TreeSet to store items in natural sorting order, we just need to implement the Comparable interface, i.e., define compareTo() function.

If we don’t require natural ordering of objects, then we can also give custom ordering to TreeSet by passing in a custom-defined Comparator class object to the TreeSet constructor.

ArrayList Vs. LinkedList in Java

  1. The ArrayList search operation is pretty fast compared to the LinkedList search, as if we know the index, we can get it in O(1) for ArrayList whereas O(N) for LinkedList.
  2. Deletion for ArrayList is O(N) in the worst case, and sometimes it can be O(1) if you’re removing the first or last element based on optimizations written. O(1) for LinkedList no matter where the position
  3. Insertion is similar to Deletion.

If the size of the list is the same throughout, then ArrayList will make more sense, but we expect to do a lot of insertions and deletions, then LinkedList is better equipped to handle this.

What is the difference between Queue and Deque?

QueueDeque
It is called a single-ended Queue.It is called a double-ended Queue.
Elements in the Queue are added or removed from one end.

Elements in the Queue that are added from either end can be added and removed from both ends.

It is less versatile.It is more versatile.

How to print a LinkedList in reverse order in Java?

We can make use of the descendingIterator() function to get a reverse iterator.

import java.util.*;
class HelloWorld {
    public static void main(String[] args) {
        LinkedList<String> test = new LinkedList<String>();
        test.add("Hello World 1");
        test.add("Hello World 2");

        var t = test.descendingIterator();

        while(t.hasNext())
            System.out.println(t.next());
    }
}

Explain about WeakHashMap in Java?

WeakHashMap is an implementation of the Map interface that stores only weak references to its keys. Keeping only weak references allows a key-value pair to be garbage-collected when its key is no longer referenced outside of the WeakHashMap.

Typically, if we were to store objects in HashMap, garbage collection would not happen unless we remove the entry from HashMap.

Let take a below example:

import java.util.*;
public class WeakHashMapExample {
   private static Map map;
   public static void main (String args[]) {
      map = new WeakHashMap();
      map.put(new String("Rahul"), "CodingJump");

      Runnable runner = new Runnable() {
         public void run() {
            while (map.containsKey("Rahul")) {
               try {
                  Thread.sleep(500);
               }catch (InterruptedException ignored) {
               }
               System.out.println("Thread waiting");
               System.gc(); // Needed so that the while condition will fail next time.
            }
         }
      };
      Thread t = new Thread(runner);
      t.start();
      System.out.println("Main waiting");
      try {
         t.join();
      }catch (InterruptedException ignored) {
      }
   }
}

System.gc() is required for the above example to stop the infinite loop that will happen as garbage collection will not occur immediately as not much memory is needed. Once System.gc() is run, the string Rahul would be garbage collected.

What happens when you add/delete HashSet or ArrayList from two or more threads?

As these collections are not thread-safe, they must be used by a single thread only, but we still need to do this when we might have to use synchronized alternatives.

If we try to modify ArrayList or HashSet by two or more threads, we will most likely get a ConcurrentModificationException.

Explain UnsupportedOperationException in Java Collections?

UnsupportedOperationException is an exception that is thrown on methods that are not supported by the actual collection type.

For example, Developer is making a read-only list using “Collections.unmodifiableList(list)” and calling call(), add() or remove() method. It should clearly throw UnsupportedOperationException.

What is CopyOnWriteArrayList?

CopyOnWriteArrayList is a variant of ArrayList in which operations like add and set are implemented by creating a copy of the array. It is thread-safe, and thereby it does not throw ConcurrentModificationException. This ArrayLists permits all the elements, including null.

Explain Map.Entry In Map Java?

We can use entrySet() to get the set view of a map having an element Map.Entry. You can also getKey() and getValue() of the Map.Entry to get the pair of keys and values.

Why there is no ConcurrentHashSet against ConcurrentHashMap

There’s no built-in type for ConcurrentHashSet because you can always derive a set from a map.You can get a concurrent hash set view via ConcurrentHashMap.newKeySet().

import java.util.*;
import java.util.concurrent.*;
public class ConcurrentHashSetExample {
     public static void main(String []args){
        var set = ConcurrentHashMap.newKeySet();
        set.add(1);
        System.out.println(set.contains(1));
     }
}

Explain a few Concurrent collections in Java?

  1. ConcurrentLinkedQueue – A ConcurrentLinkedQueue is an unbounded, thread-safe, and non-blocking queue.
  2. ConcurrentHashMap – Concurrent HashMap, better implementation of Hashtable
  3. ConcurrentSkipListMap – The map is sorted according to the natural ordering of its keys
  4. BlockingQueue – Blocking nature queues makes it easy to implement Producer and Consumer patterns.
  5. CopyOnWriteArrayList, CopyOnWriteHashSet – Allows for concurrent access of ArrayList; this is done by creating copies while writing new elements.is the preferred option ONLY WHEN there are very less number of writes and a huge number of reads

Synchronized vs. Concurrent Collections

Synchronized collections like synchronized HashMap, Hashtable, HashSet, Vector, and synchronized ArrayList are much slower than their concurrent counterparts.

Synchronized collections archives thread-safety primarily by locking while reading/writing, whereas Concurrent collections achieve it by some sophisticated techniques.

What is wrong with HashMap in a multithreaded environment? When Get() goes into an infinite loop?

Using HashMap in a multi-threaded environment is fine till we just use it as read-only. But if we use Put(), then as Put() causes resizing, when you use Get(), it causes an infinite loop.

To resolve that, we can use Hashtable or a ConcurrentHashMap. ConcurrentHashMap is even better as it’s built for that purpose.

Differences between HashMap and Hashtable in Java?

HashMap is non synchronized. It is not-thread safe and can’t be shared between many threads without proper synchronization code, whereas Hashtable is synchronized. It is thread-safe and can be shared with many threads.

HashMap allows one null key and multiple null values, whereas Hashtable doesn’t allow any null key or value.

HashMap is generally preferred over HashTable if thread synchronization is not needed.

If we have two class objects which are added to HashSet then what will be the count?

Each object instance created from the same class would have different hashCode() and would be present in different memory location.

So when we add those objects to the HashSet then it would have a size of two. If we need to have only one entry then we will need to override both hashCode() and equals() method like shown below.

import java.io.*;
import java.util.*;

class Test {
    @Override
    public int hashCode() {
        return 1;
    }

    @Override
    public boolean equals(Object o) {
        return true;
    }
}
public class HashSetExample {
    public static void main(String[] args)
    {
        HashSet<Test> testMap = new HashSet<>();
        testMap.add(new Test());
        testMap.add(new Test());
        System.out.println(testMap.size());
    }
}