Practice commonly asked
Collections interview questions with clear answers and explanations.
30
Interview Questions
Questions & Answers
Collections Interview Questions
30 Questions
Q 1
What is the memory complexity and garbage collection impact of large LinkedList vs ArrayList?
Hard
Answer
LinkedList has significantly higher memory overhead because every element is wrapped in a Node object (24 bytes overhead per node for pointers). It creates many small objects, putting heavy pressure on GC compared to contiguous array storage in ArrayList.
Explanation
ArrayList elements are stored in contiguous memory arrays, which improves CPU cache hit ratios and minimizes Garbage Collector tracking overhead.
Code Example
Java
// ArrayList: Single array object holding references
List<Integer> aList = new ArrayList<>(1000);
// LinkedList: 1000 individual Node objects on Heap!
List<Integer> lList = new LinkedList<>();
Reference:
Java Collections Framework
Q 2
What is Checked Collections (Collections.checkedCollection) and when is it useful?
Hard
Answer
Checked collections (e.g. Collections.checkedList) return a dynamically type-safe view that validates element type at runtime, throwing ClassCastException immediately if an invalid type is inserted.
Explanation
They are useful for debugging raw type collection pollution issues when legacy non-generic code interacts with modern generic collections.
Code Example
Java
List rawList = new ArrayList<String>();
List<String> checkedList = Collections.checkedList(rawList, String.class);
// Raw reference insertion attempt throws ClassCastException immediately:
// rawList.add(123);
// checkedList.add(123); // Throws ClassCastException at insertion point!
Reference:
Java Collections Framework
Q 3
What is the difference between Collection.toArray() and Collection.toArray(T[] a)?
Easy
Answer
toArray() returns Object[], which loses specific element type safety. toArray(T[] a) returns an array of type T. Passing String[]::new (generator in Java 11+) is the modern type-safe standard.
Explanation
Using generator function syntax list.toArray(String[]::new) avoids pre-allocating empty dummy arrays.
Code Example
Java
List<String> list = List.of("A", "B");
// Modern type-safe conversion:
String[] arr = list.toArray(String[]::new);
Reference:
Java Collections Framework
Q 4
How does Stream.collect(Collectors.toMap()) handle duplicate keys?
Medium
Answer
By default, Collectors.toMap(keyMapper, valueMapper) throws IllegalStateException if duplicate keys are encountered. A merge function parameter must be provided to handle duplicates.
Explanation
The binary merge operator (existingValue, replacementValue) -> chosenValue defines how to resolve duplicate key collisions during stream collection.
Code Example
Java
List<String> list = List.of("apple", "banana", "apricot");
Map<Character, String> map = list.stream()
.collect(Collectors.toMap(
s -> s.charAt(0),
s -> s,
(existing, replacement) -> existing + "," + replacement // Merge function
));
Reference:
Java Collections Framework
Q 5
What is TreeMultiset or MultiMap in Java, and how is it simulated in standard Collections?
Medium
Answer
Standard Java Collections do not have built-in MultiMap or MultiSet interfaces. They are typically simulated using Map<K, List<V>> or Map<K, Set<V>>, or imported from Guava/Apache Commons libraries.
Explanation
Map.computeIfAbsent simplifies simulating MultiMap structures in standard Java 8+.
Code Example
Java
Map<String, List<String>> multiMap = new HashMap<>();
// MultiMap insertion using computeIfAbsent:
multiMap.computeIfAbsent("CategoryA", k -> new ArrayList<>()).add("Item1");
multiMap.computeIfAbsent("CategoryA", k -> new ArrayList<>()).add("Item2");
Reference:
Java Collections Framework
Q 6
How does Map.replace() and Map.replaceAll() work in Java 8?
Medium
Answer
replace(key, value) updates value only if key is mapped. replace(key, oldVal, newVal) updates only if currently mapped to oldVal. replaceAll(biFunction) replaces values of all entries with result of function.
Explanation
replaceAll is useful for bulk transformation of all values inside a Map instance.
Code Example
Java
Map<String, Integer> map = new HashMap<>();
map.put("a", 1);
map.put("b", 2);
map.replaceAll((k, v) -> v * 10); // Values become 10 and 20
Reference:
Java Collections Framework
Q 7
What is Collections.rotate(), swap(), and fill()?
Easy
Answer
rotate(list, distance) rotates list elements by distance. swap(list, i, j) swaps elements at indices i and j. fill(list, obj) replaces all elements in the list with the specified object.
Explanation
These static helper operations modify the backing list in place.
Code Example
Java
List<String> list = new ArrayList<>(List.of("A", "B", "C", "D"));
Collections.swap(list, 0, 3); // Swaps A and D -> ["D", "B", "C", "A"]
Collections.rotate(list, 1); // Rotates right -> ["A", "D", "B", "C"]
Reference:
Java Collections Framework
Q 8
How does Collections.binarySearch() work and what are its prerequisites?
Medium
Answer
Collections.binarySearch() performs O(log n) binary search on a sorted list. The list MUST be sorted in ascending order beforehand, otherwise the search result is undefined.
Explanation
If element is found, it returns the non-negative index. If not found, it returns (-(insertion point) - 1).
Code Example
Java
List<Integer> list = new ArrayList<>(List.of(10, 20, 30, 40));
Collections.sort(list); // Prerequisite
int index = Collections.binarySearch(list, 30); // Returns 2
Reference:
Java Collections Framework
Q 9
What is the difference between Properties and standard Map in Java?
Medium
Answer
Properties is a legacy class extending Hashtable that represents a persistent set of properties where keys and values are both Strings. It supports loading from and saving to stream/file formats.
Explanation
Properties is widely used in Java configuration management for loading .properties configuration files.
What is the difference between HashMap and Hashtable in Java?
Easy
Answer
Hashtable is a legacy class where methods are synchronized (thread-safe but slow) and disallows null keys/values. HashMap is unsynchronized, faster, and allows one null key and multiple null values.
Explanation
ConcurrentHashMap or Collections.synchronizedMap should be used instead of Hashtable in modern multithreaded code.
What is Collections.singletonList(), singletonSet(), and singletonMap()?
Easy
Answer
They return immutable single-element collection instances. They save memory when passing exactly one element to methods expecting a collection interface.
Explanation
Attempts to modify a singleton collection (add, remove, clear) throw UnsupportedOperationException.
What is Collections.emptyList(), emptySet(), and emptyMap() and why use them?
Easy
Answer
They return immutable type-safe empty collections. They are preferred over returning null or creating new collection objects to avoid NullPointerExceptions and allocation overhead.
Explanation
They return shared singleton instances internally, saving memory compared to instantiation of new empty ArrayList or HashMap instances.
Code Example
Java
public List<String> getUserRoles(User user) {
if (user == null) {
return Collections.emptyList(); // Avoids returning null
}
return user.getRoles();
}
Reference:
Java Collections Framework
Q 13
What is the difference between Map.getOrDefault() and Map.putIfAbsent()?
Easy
Answer
getOrDefault(key, default) returns the mapped value or default if key is absent without mutating the map. putIfAbsent(key, value) inserts key-value pair into the map if key is missing or mapped to null.
Explanation
Use getOrDefault when reading non-existent keys safely without modifying map contents.
What is the behavior of Map.ofEntries() and Map.entry() in Java 9+?
Medium
Answer
Map.ofEntries() allows creating unmodifiable maps with an arbitrary number of key-value pairs using Map.entry(key, value) helper methods.
Explanation
Unlike Map.of() which is limited to 10 key-value pairs via overloaded methods, Map.ofEntries handles any number of key-value pairs via varargs while guaranteeing immutability.
How does Collections.frequency() and Collections.disjoint() work?
Easy
Answer
Collections.frequency(collection, object) counts occurrences of an object in a collection. Collections.disjoint(c1, c2) returns true if two collections have no elements in common.
Explanation
Collections.disjoint is optimized based on collection types; if one argument is a Set, lookup runs faster.
What is PriorityBlockingQueue and how does it handle concurrency?
Hard
Answer
PriorityBlockingQueue is an unbounded thread-safe blocking queue that uses the same ordering rules as PriorityQueue and supplies blocking retrieval operations using a main ReentrantLock.
Explanation
Because it is unbounded, put() never blocks due to capacity limits (though it may throw OutOfMemoryError if memory runs out). take() blocks when empty.
Code Example
Java
BlockingQueue<Integer> pbq = new PriorityBlockingQueue<>();
pbq.offer(50);
pq.offer(10);
System.out.println(pbq.take()); // Retrieves 10 (lowest priority value first)
Reference:
Java Collections Framework
Q 17
What is the role of ensureCapacity() and trimToSize() in ArrayList?
Easy
Answer
ensureCapacity(int minCapacity) pre-allocates underlying array storage to avoid repeated re-allocations during bulk insertions. trimToSize() reduces capacity down to the current list size to minimize memory consumption.
Explanation
Use ensureCapacity when adding thousands of items in a loop to eliminate intermediate array allocations.
Code Example
Java
ArrayList<Integer> list = new ArrayList<>();
list.ensureCapacity(10000); // Pre-allocates memory for 10k items
for (int i = 0; i < 100; i++) list.add(i);
list.trimToSize(); // Trims capacity down to 100
Reference:
Java Collections Framework
Q 18
How does dynamic array resizing work in ArrayList?
Medium
Answer
When an ArrayList reaches capacity, it creates a new array with 50% larger capacity (newCapacity = oldCapacity + (oldCapacity >> 1)) and copies elements from the old array using Arrays.copyOf().
Explanation
Initial default capacity of ArrayList is 10 (when first element is added). Resizing is an O(n) operation, but amortized insertion time remains O(1).
Code Example
Java
ArrayList<Integer> list = new ArrayList<>(10);
// When 11th element is added, capacity expands to 10 + (10 >> 1) = 15
for (int i = 0; i < 11; i++) {
list.add(i);
}
Reference:
Java Collections Framework
Q 19
What is ListIterator and how does it differ from a standard Iterator?
Medium
Answer
ListIterator extends Iterator specifically for List implementations. It allows bi-directional traversal (hasPrevious, previous), element modification (set, add), and retrieving current index positions.
Explanation
Standard Iterator only moves forward and supports remove(). ListIterator allows moving backward, inserting elements during iteration, and updating existing elements.
Code Example
Java
List<String> list = new ArrayList<>(List.of("A", "B", "C"));
ListIterator<String> lit = list.listIterator();
while (lit.hasNext()) {
if (lit.next().equals("B")) {
lit.set("Beta"); // Replaces element at current position
}
}
Reference:
Java Collections Framework
Q 20
What is the difference between Iterable and Iterator in Java?
Easy
Answer
Iterable is a top-level interface representing a data structure that can be iterated over using a for-each loop. Iterator is an interface that provides mechanisms (hasNext, next, remove) to traverse elements sequentially.
Explanation
Any class implementing Iterable can be used in enhanced for-loops. The iterable interface defines iterator() which returns an Iterator instance.
Code Example
Java
List<String> list = List.of("A", "B");
// Using Iterable interface via for-each loop:
for (String item : list) {
System.out.println(item);
}
// Using Iterator directly:
Iterator<String> it = list.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
Reference:
Java Collections Framework
Q 21
Why is Vector considered a legacy class and what replaced it?
Easy
Answer
Vector synchronizes every individual method call using internal synchronized locks, causing high performance overhead even in single-threaded execution. It was replaced by ArrayList and CopyOnWriteArrayList / Collections.synchronizedList.
Explanation
Vector was part of Java 1.0 before the Collections Framework was introduced in Java 1.2. It is retained strictly for backward compatibility.
Code Example
Java
// Legacy Vector usage:
Vector<String> v = new Vector<>();
v.add("Legacy"); // Method is synchronized internally
// Modern replacement:
List<String> list = new ArrayList<>();
Reference:
Java Collections Framework
Q 22
What are SequencedCollection, SequencedSet, and SequencedMap introduced in Java 21?
Hard
Answer
Introduced in Java 21, SequencedCollection provides unified APIs for collections with defined encounter order, featuring explicit first/last element operations (getFirst(), getLast(), addFirst(), addLast(), reversed()).
Explanation
This interface standardizes access across ArrayList, Deque, LinkedHashSet, TreeSet, etc., making first/last and reverse operations consistent across all ordered collections.
Code Example
Java
SequencedCollection<String> list = new ArrayList<>(List.of("A", "B", "C"));
System.out.println(list.getFirst()); // "A"
System.out.println(list.getLast()); // "C"
SequencedCollection<String> reversed = list.reversed(); // View in reverse order
Reference:
Java Collections Framework
Q 23
What is TransferQueue and how does put() differ from transfer()?
Hard
Answer
TransferQueue extends BlockingQueue. While put() inserts an element and continues if capacity allows, transfer() blocks the producer thread until a consumer explicitly takes the element.
Explanation
LinkedTransferQueue implements TransferQueue and provides tryTransfer() to conditionally hand off messages instantly if a consumer is already waiting.
Code Example
Java
TransferQueue<String> tQueue = new LinkedTransferQueue<>();
// In a worker thread:
// tQueue.transfer("Message"); // Blocks until another thread consumes it!
Reference:
Java Collections Framework
Q 24
What is the difference between LinkedBlockingQueue and ArrayBlockingQueue?
Hard
Answer
ArrayBlockingQueue is bounded, array-backed, and uses a single ReentrantLock for both put and take operations. LinkedBlockingQueue is node-backed, can be bounded or unbounded, and uses two separate locks (putLock and takeLock) for higher concurrency.
Explanation
Because LinkedBlockingQueue uses separate locks for producers and consumers, threads can offer and poll simultaneously without blocking each other.
Code Example
Java
BlockingQueue<String> arrayQ = new ArrayBlockingQueue<>(100); // Fixed size array
BlockingQueue<String> linkedQ = new LinkedBlockingQueue<>(100); // Separate lock concurrency
Reference:
Java Collections Framework
Q 25
How does Map.merge() work in Java 8+?
Medium
Answer
Map.merge(key, value, remappingFunction) inserts the value if key is absent. If key is present, it computes a new value using the remapping function applied to old and new values.
Explanation
If the remapping function returns null, the entry is removed from the map altogether. It simplifies word counting and aggregation logic.
What are Java 10's Collectors.toUnmodifiableList(), toUnmodifiableSet(), and toUnmodifiableMap()?
Medium
Answer
They are Stream collectors introduced in Java 10 that collect stream elements into unmodifiable collections that reject null values and throw UnsupportedOperationException on modification.
Explanation
Unlike Collectors.toList() which returns a mutable implementation (typically ArrayList), unmodifiable collectors guarantee complete immutability of the final collected object.
What is the result of using a mutable object as a HashMap key?
Hard
Answer
If a key object is mutated after being added to a HashMap such that its hashCode or equals evaluation changes, the entry becomes 'lost' in the wrong bucket and cannot be retrieved via get().
Explanation
HashMap keys should always be immutable (like String, Integer, or record classes) to guarantee consistent hash code values throughout the object's life cycle.
Code Example
Java
class MutableKey {
int id;
MutableKey(int id) { this.id = id; }
public int hashCode() { return id; }
}
MutableKey key = new MutableKey(1);
Map<MutableKey, String> map = new HashMap<>();
map.put(key, "Value");
key.id = 2; // Mutates hash code!
System.out.println(map.get(key)); // Returns null!
Reference:
Java Collections Framework
Q 28
How do retainAll() and removeAll() behave in Java Collections?
Easy
Answer
removeAll(Collection<?> c) removes all elements present in the specified collection (difference operation). retainAll(Collection<?> c) retains only elements that exist in the specified collection (intersection operation).
Explanation
Both methods modify the target collection in-place and return true if the collection was altered as a result of the call.
What is ConcurrentSkipListMap and ConcurrentSkipListSet?
Hard
Answer
ConcurrentSkipListMap and ConcurrentSkipListSet are thread-safe, lock-free sorted concurrent collections based on SkipList data structures, offering expected O(log n) time complexity.
Explanation
They serve as thread-safe concurrent alternatives to TreeMap and TreeSet, handling high concurrent read/write throughput without global locking.
Code Example
Java
ConcurrentNavigableMap<Integer, String> map = new ConcurrentSkipListMap<>();
map.put(3, "Three");
map.put(1, "One");
map.put(2, "Two");
// Maintained in sorted order concurrently: 1, 2, 3
Reference:
Java Collections Framework
Q 30
What is EnumMap and why is it performance-superior for Enum keys?
Medium
Answer
EnumMap is a specialized Map implementation for enum keys backed internally by a compact Java array. It eliminates hashing overhead and offers extremely fast constant-time performance.
Explanation
Because enum constants have fixed sequential ordinal numbers, EnumMap uses array index offsets directly rather than hash computation or collision management.
Code Example
Java
enum Day { MON, TUE, WED }
Map<Day, String> schedule = new EnumMap<>(Day.class);
schedule.put(Day.MON, "Work");
schedule.put(Day.TUE, "Training");
Reference:
Java Collections Framework
About This Topic
Prepare for
Collections interviews with important concepts
and commonly asked questions.