Here is a list of Java Collections interview Questions. These are some of the famous questions asked in interviews.

Java Collections Interview Questions

What is rehashing? When is it done?

In the case of a HashMap, there are two important member fields which determine when exactly the resizing of the map needs to be done. They are loadFactor and capacity. If we don’t specify these two while creating a new HashMap (i.e., we don’t call parameterized constructor that takes these two arguments, but call the no-arg constructor), the new HashMap will be created with default loadFactor of 0.75 and default initial capacity of 16.

As soon as the size of the Map grows and reaches 75%, it would construct a new Map with 50% more capacity than the current capacity. The elements of the HashMap are copied after doing a new hash on the newly constructed HashMap. This process is known as rehashing.

How does the HashMap’s Iterator detect a modification and throw ConcurrentModificationException?

HashMap’s iterator is a fail-fast iterator. It means, if any modification is done on the underlying collection during iteration, then the iterator should stop iterating and throw ConcurrentModificationException. HashMap achieves this by keeping track of the number of modifications. HashMap has an internal integer member field named modCount. This is incremented each time a user invokes methods like put(), remove(), putAll(), clear(), etc modifying the data structure. When the iterator is created, a similar field maintained in Iterator implementation class called iteratorModCount is initialized with HashMap’s modCount. During iteration, these values are checked, and ConcurrentModificationException is thrown if they are not equal.

Why Map interface does not extend java.util.Collection?

Map interface requires a Key as well as Value for its operations, but Collection requires only one parameter. The keyset() and values() operation provide the keys and values stored in a map, but there are not functions similar to this in java.util.Collection. Due to this incompatibility, Map interface does not extend java.util.Collection.

What is a hash collision? How is it handled in case of a HashMap or a HashTable?

For HashMap or a HashTable, the appropriate bucket in which the Entry<K,V> data shall go during a Map.put(K,V) operation is determined by using K.hashCode(). If two keys give the same hashcode, then both the corresponding entries are destined to go under the same bucket. This scenario is known as a hash collision. If such a case occurs, the HashMap or HashTable stores them in the form of a list under the same bucket. While retrieving, K.equals() method is invoked to get the right Entry<K,V> and retrieve the appropriate value from that. You can read the first two questions of Core Java Interview Questions

What is the difference between poll() and remove() in a PriorityQueue?

queue.poll() and queue.remove() retrieves the head element of the queue. The remove() function will throw a NoSuchElementException if the queue is empty at the time of its execution whereas the poll() function returns a null value in a similar case.

What is the difference between ArrayList and a Vector?

Vector is a legacy class. It is synchronized. If Vector reaches its max size, the underlying array that backs the vector is discarded after creating a new array with double the size of the initial array.



ArrayList was introduced in release 1.2. It was added later as a part of collections framework enhancements. It is not synchronized. If the ArrayList is about to reach its maximum capacity, the underlying array that backs the ArrayList is discarded after creating a new Array with 50% more size than the original Array.

How can we iterate over a TreeMap?

There are three ways in which we can iterate over a TreeMap – using for loop for Map.Entry and using iterators for keyset() as well as entrySet().

import java.util.*; public class TreeMapTest{ public static void main(String[] args){ TreeMap<String,String> treeMap = new TreeMap<String, String>(); treeMap.put("a", "apple"); treeMap.put("c", "cherry"); treeMap.put("p", "pear"); // using modified for loop over entrySet for(Map.Entry<String, String> e: treeMap.entrySet()){ String key = e.getKey(); String value = e.getValue(); System.out.println(key + " : " + value); } // using keyset iterator Set keySet = treeMap.keySet(); for(Iterator i = keySet.iterator(); i.hasNext();){ String key = (String)i.next(); String value = (String)treeMap.get(key); System.out.println(key + " : " + value); } // using entrySet iterator Iterator entriesIter = treeMap.entrySet().iterator(); while(entriesIter.hasNext()){ Map.Entry<String, String> entry = (Map.Entry<String, String>)entriesIter.next(); String key = entry.getKey(); String value = entry.getValue(); System.out.println(key + " : " + value); } } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 import java . util . * ; public class TreeMapTest { public static void main ( String [ ] args ) { TreeMap < String , String > treeMap = new TreeMap < String , String > ( ) ; treeMap . put ( "a" , "apple" ) ; treeMap . put ( "c" , "cherry" ) ; treeMap . put ( "p" , "pear" ) ; // using modified for loop over entrySet for ( Map . Entry < String , String > e : treeMap . entrySet ( ) ) { String key = e . getKey ( ) ; String value = e . getValue ( ) ; System . out . println ( key + " : " + value ) ; } // using keyset iterator Set keySet = treeMap . keySet ( ) ; for ( Iterator i = keySet . iterator ( ) ; i . hasNext ( ) ; ) { String key = ( String ) i . next ( ) ; String value = ( String ) treeMap . get ( key ) ; System . out . println ( key + " : " + value ) ; } // using entrySet iterator Iterator entriesIter = treeMap . entrySet ( ) . iterator ( ) ; while ( entriesIter . hasNext ( ) ) { Map . Entry < String , String > entry = ( Map . Entry < String , String > ) entriesIter . next ( ) ; String key = entry . getKey ( ) ; String value = entry . getValue ( ) ; System . out . println ( key + " : " + value ) ; } } }

When would you use a LinkedHashMap?

A LinkedHashMap is one of the implementations available for the Map interface. LinkedHashMap keeps the order of the insertion of the elements. So LinkedHashMap may be used when a client is expecting that the items are returned in the same order as they are stored.

What is a BlockingQueue?

A BlockingQueue is an implementation of Queue interface. It is available under java.util.concurrent package. It is a thread-safe queue.

A null value is not permitted in a BlockingQueue, and hence it will throw a NullPointerException on any attempt to do so by add, offer or put methods. If the value retrieved is null in case of a queue.poll(), it indicates that something has gone wrong in the BlockingQueue.

BlockingQueue is typically used to solve problems that are similar to the producer-consumer problem. A simple example is shown in the diagram below:

In the above diagram, a producer thread creates items and puts them to the blocking queue and a consumer thread takes out items via poll operation in order to do further processing. If the queue is already full, the producer thread will be blocked and waits till the consumer takes an element from the queue, thus, creating space for the new queue member. Similarly, if the queue is already empty, the consumer thread will wait till the producer thread adds a new element to the queue. What is the difference between a ListIterator and an Iterator? Using an Iterator, we can traverse a List, Set or a Map. In fact, the method iterator() is from the super interface java.util.Collection and concrete classes contain specific implementations to get the iterator for particular Collection interface type. The important methods associated with Iterators are: hasNext()

next()

remove() Iterators allow traversal only in the forward direction. ListIterator, as the name suggests, can be used to traverse only a list. An instance of the ListIterator can be obtained by calling List.listiterator(). ListIterator allows you to traverse in both forward and backward directions. Thus, in addition to the above three methods which the ListIterator shares in common with Iterator, the following methods are also added to it: previous()

hasPrevious()

previousIndex()

nextIndex() A ListIterator does not have the concept of a current element. Its position would always be in between two elements in the list as shown in the illustration below:

The figure illustrates a simple list with four elements. Let us see some important features regarding the ListIterator interface by keeping the above diagram as a reference. The methods previousIndex() and nextIndex() in this example will return 0 and 1 respectively as those are the indices of Element1 and Element2.

If the cursor position is before Element1, a call to previousIndex() will return -1 as there are no elements before Element1. A call to hasPrevious() at this point would return false.

If the cursor position is after Element4, a call to nextIndex() will return the size of the list. A call to hasNext() at this point would return false. When should we use a WeakHashMap? A WeakHashMap is an implementation of the Map interface in which it stores only weak references to the keys. This is a special purpose Map implementation.

To understand it better, let us see an overview of Garbage Collection process in Java. JVM’s garbage collection thread wakes up at certain times and does the garbage collection for eligible objects in memory. This process is dependent on the type of references to that object. Garbage collection is done eagerly if all the references which are pointing to the object are WeakReferences. When there is a memory shortage in JVM, objects with SoftReference are collected to reclaim some memory.

WeakHashMap allows you to garbage collect the key-value pairs when the references to the key are only the weak reference. This is used in special cases like maintaining a registry entry or a lookup cache where you need to keep the values as long as there is an external reference. If there is no external strong reference, the entry for the key will be garbage collected. What is the difference between Collection.remove() and Iterator.remove()? Collection interface’s remove method has the following signature: public boolean remove(Object o) This method removes the specified element if it is present in the collection and returns true if removal is successful. The function will throw a ClassCastException for an incompatible input, NullPointerException for a null input and UnsupportedOperationException if the underlying collection doesn’t support this operation. Iterator’s remove method has the following signature: public void remove() This method would remove the last element that was returned by the next() call. This method can be called only once per call to the next() method. Otherwise, it would throw an IllegalStateException. In the case of a fail-fast iterator, it will throw an UnsupportedOperationException if remove() is invoked during traversal of the supporting collection. What is the difference between a HashSet and a TreeSet? HashSet internally uses a HashMap to store data. As a result, the elements are not ordered. Since hashing is used for finding the bucket in which the key-value pairs go, methods like add, remove and contains, return the results in constant time O(1).

From TreeSet internal implementation, we can see that a NavigableMap tree structure backs it. TreeSet has the elements sorted in natural order. All the classes that implement Comparable can be added to the TreeSet. So all the Wrapper classes like String, Integer, etc. can be added to the TreeSet. A TreeSet also has a constructor that accepts Comparator, which allows adding classes that don’t implement Comparable. If TreeSet is not initialized with Comparator, and the objects being added do not implement Comparable a java.lang.ClassCastException is thrown What is the difference between a Synchronized Collection and a Concurrent Collection? For a given collection, you can get a synchronized collection backed by given collection from Collections utility class using methods like Collections.synchronizedList(), Collections.synchronizedSet(), etc. The user must manually synchronize over the returned collection while iterating over it and making any changes as the collection cannot be modified by multiple threads simultaneously. The utility class provides methods to get the thread-safe version of a map also.

Concurrent collections are those collections available as a part of java.util.concurrent package. These are designed to be thread-safe and allows multiple threads to access different parts of the collection at a given point of time. These collections, in contrast to their synchronized counterparts, do not use a common lock over the full collection. Instead, they are divided into sub-regions and each region is set with a separate lock. Multiple threads, can thus, access the collection but for a single region, only one thread can gain access at a particular time. What is ConcurrentLinkedDeque? It is a thread-safe implementation for a Deque. Similar to many other implementations under java.util.concurrent package, a ConcurrentLinkedDeque does not allow null inputs. Because they are asynchronous in nature, iterating values from the collection will not return correct values if at the same time another thread is modifying the collection. It implements all optional methods of Deque interface. For a given TreeMap, how can we find out the position for a given entry? Since you add elements to a TreeMap, the keys will be already sorted and ordered in the natural order. You can copy the keys to an array and use Arrays.binarySearch() to find the index of given key.

Share this: Facebook

LinkedIn

Twitter

Tumblr

Pinterest



Like this: Like Loading...