Collections

Practice commonly asked Collections interview questions with clear answers and explanations.

19 Interview Questions

Collections Interview Questions

19 Questions
Q 61

What is the difference between Stream.collect() and Collection methods for bulk operations?

Medium
Answer
Collection bulk methods (addAll, removeAll, retainAll) modify the target collection in place synchronously. Stream.collect() constructs a new result structure declaratively using functional pipelines without mutating the source collection.
Explanation
Streams enable functional transformations (filter, map) and easy parallel processing via parallelStream().
Code Example Java
List<Integer> list = List.of(1, 2, 3, 4, 5);
List<Integer> evenSquares = list.stream()
    .filter(n -> n % 2 == 0)
    .map(n -> n * n)
    .collect(Collectors.toList());
Reference: Java Collections Framework
Q 62

How do SequencedCollections (Java 21) simplify ordered collection operations?

Medium
Answer
SequencedCollection, SequencedSet, and SequencedMap introduce uniform methods across ordered collections for accessing first/last elements (getFirst(), getLast(), addFirst(), addLast(), removeFirst(), removeLast()) and obtaining a reverse view (reversed()).
Explanation
Before Java 21, getting the last element differed across structures (e.g. list.get(list.size()-1) vs deque.getLast() vs sortedSet.last()). SequencedCollections unifies this API.
Code Example Java
SequencedCollection<String> seq = new ArrayList<>(List.of("A", "B", "C"));
System.out.println(seq.getFirst()); // "A"
System.out.println(seq.getLast());  // "C"
SequencedCollection<String> rev = seq.reversed(); // Reversed view
Reference: Java Collections Framework
Q 63

What is WeakHashMap and how does it prevent memory leaks?

Hard
Answer
WeakHashMap stores keys as WeakReferences. If a key object no longer has any strong references outside the map, the Garbage Collector reclaims it and the entry is automatically removed from the map.
Explanation
WeakHashMap is frequently used for building memory-sensitive caches or associating temporary metadata with active domain objects.
Code Example Java
Map<Object, String> weakMap = new WeakHashMap<>();
Object keyObj = new Object();
weakMap.put(keyObj, "Cached Metadata");

keyObj = null; // Key is now weakly reachable
System.gc();   // GC will clear the entry from weakMap
Reference: Java Collections Framework
Q 64

What is IdentityHashMap and when is reference equality preferred over equals()?

Hard
Answer
IdentityHashMap uses reference equality (==) instead of logical equality (equals()) for key comparison. It is used during graph serialization, object tree cloning, or framework proxy tracking where distinct object instances must be tracked regardless of value equality.
Explanation
IdentityHashMap deliberately breaks Map contract compliance by ignoring equals() and hashCode() override implementations.
Code Example Java
Map<String, String> map = new IdentityHashMap<>();
String s1 = new String("key");
String s2 = new String("key");
map.put(s1, "Val1");
map.put(s2, "Val2");
System.out.println(map.size()); // Prints 2 because s1 != s2 by reference
Reference: Java Collections Framework
Q 65

What is Map.computeIfAbsent() vs Map.putIfAbsent()?

Easy
Answer
putIfAbsent(key, value) evaluates the value eagerly before insertion. computeIfAbsent(key, mappingFunction) evaluates the mapping function lazily ONLY if the key is missing or mapped to null.
Explanation
computeIfAbsent is ideal when value creation is expensive or involves constructing new nested collection objects.
Code Example Java
Map<String, List<String>> map = new HashMap<>();
// Efficient lazy initialization:
map.computeIfAbsent("Java", k -> new ArrayList<>()).add("Spring");
Reference: Java Collections Framework
Q 66

What is the difference between SynchronousQueue and ArrayBlockingQueue?

Hard
Answer
ArrayBlockingQueue has a fixed capacity buffer holding queued items. SynchronousQueue has zero internal capacity; put() blocks until another thread calls take(), acting as a direct handoff queue between producer and consumer threads.
Explanation
Executors.newCachedThreadPool() uses SynchronousQueue to pass tasks instantly to available or newly spawned threads without queuing.
Code Example Java
BlockingQueue<String> syncQ = new SynchronousQueue<>();
// Producer thread put() blocks until Consumer thread calls take()
Reference: Java Collections Framework
Q 67

How does PriorityQueue order its elements, and what is its time complexity?

Medium
Answer
PriorityQueue orders elements according to natural order or a specified Comparator using a binary min-heap array. Offer and poll operations take O(log n) time, while peek takes O(1) time.
Explanation
PriorityQueue does not guarantee sorted order during direct iteration (e.g. for-each loop); elements are only retrieved in priority order via poll() or peek().
Code Example Java
PriorityQueue<Integer> pq = new PriorityQueue<>(Comparator.reverseOrder()); // Max-heap
pq.offer(10);
pq.offer(30);
pq.offer(20);
System.out.println(pq.poll()); // Retrieves 30 (highest value first)
Reference: Java Collections Framework
Q 68

How do List.of() factory methods differ from Collections.unmodifiableList()?

Medium
Answer
List.of() creates a truly immutable collection instance that disallows null elements. Collections.unmodifiableList() creates an unmodifiable view wrapped around an underlying list that can still be mutated via the direct backing list reference.
Explanation
List.of() is null-hostile (throws NullPointerException if any element is null), while Collections.unmodifiableList allows nulls if the backing list allows them.
Code Example Java
List<String> mutable = new ArrayList<>(Arrays.asList("A", null));
List<String> view = Collections.unmodifiableList(mutable);
mutable.add("B"); // Modifies backing list and view!

// List<String> immutable = List.of("A", null); // Throws NullPointerException
Reference: Java Collections Framework
Q 69

What is the difference between ArrayDeque and LinkedList when used as a Queue or Stack?

Medium
Answer
ArrayDeque is backed by a circular array buffer and provides faster performance, lower memory usage, and no garbage collection overhead per element. LinkedList allocates Node objects on the heap for every element. ArrayDeque is recommended over both Stack and LinkedList for queue/deque tasks.
Explanation
ArrayDeque does not allow null elements, whereas LinkedList permits nulls.
Code Example Java
Deque<String> stack = new ArrayDeque<>();
stack.push("A");
stack.push("B");
System.out.println(stack.pop()); // Returns "B"
Reference: Java Collections Framework
Q 70

What is the difference between TreeSet, HashSet, and LinkedHashSet?

Medium
Answer
HashSet offers unordered storage with O(1) performance. LinkedHashSet maintains insertion order via a doubly-linked list. TreeSet maintains element order (natural or Comparator) using a Red-Black Tree with O(log n) performance.
Explanation
TreeSet does not allow null elements if using natural ordering because null cannot be compared via compareTo().
Code Example Java
Set<String> set1 = new HashSet<>(List.of("B", "A", "C"));      // Unordered
Set<String> set2 = new LinkedHashSet<>(List.of("B", "A", "C"));// Insertion order: B, A, C
Set<String> set3 = new TreeSet<>(List.of("B", "A", "C"));      // Sorted order: A, B, C
Reference: Java Collections Framework
Q 71

What is CopyOnWriteArrayList and what is its performance trade-off?

Medium
Answer
CopyOnWriteArrayList creates a new copy of the underlying array whenever a write operation (add, set, remove) occurs. It provides thread-safe, lock-free iteration over immutable array snapshots.
Explanation
Trade-off: Extremely fast for read operations, but memory-intensive and slow for write operations. Best suited for read-heavy event listener lists.
Code Example Java
List<String> listeners = new CopyOnWriteArrayList<>();
listeners.add("Listener1");

// Safe concurrent traversal without ConcurrentModificationException
for (String l : listeners) {
    System.out.println(l);
}
Reference: Java Collections Framework
Q 72

How does HashSet store elements internally?

Medium
Answer
HashSet is backed internally by a HashMap instance. Elements added to the HashSet are stored as keys in the internal HashMap, associated with a constant dummy Object value (PRESENT).
Explanation
Because HashMap keys must be unique, HashSet automatically enforces element uniqueness utilizing HashMap's key deduplication mechanism.
Code Example Java
// Simplified JDK HashSet implementation concept:
public class SimpleHashSet<E> {
    private transient HashMap<E, Object> map = new HashMap<>();
    private static final Object PRESENT = new Object();

    public boolean add(E e) {
        return map.put(e, PRESENT) == null;
    }
}
Reference: Java Collections Framework
Q 73

What is the difference between Comparable and Comparator interfaces?

Easy
Answer
Comparable defines natural sorting logic inside the class via compareTo(T o). Comparator defines external custom sorting logic via compare(T o1, T o2) and allows multiple sorting strategies.
Explanation
Use Comparable for a default natural ordering (e.g. String, Integer). Use Comparator for dynamic or multiple sort orders (e.g. sort by name, then age).
Code Example Java
List<Emp> emps = getEmployees();
// Natural order (Comparable):
Collections.sort(emps);

// Custom order (Comparator lambda):
emps.sort(Comparator.comparing(Emp::getSalary).reversed());
Reference: Java Collections Framework
Q 74

What is the architectural difference between ArrayList and LinkedList, and when should each be used?

Medium
Answer
ArrayList uses a contiguous dynamic array offering O(1) random access and excellent CPU cache performance. LinkedList uses a doubly-linked list with O(n) access time and higher memory overhead per node. ArrayList is preferred for almost all general-purpose use cases.
Explanation
Despite LinkedList having O(1) insertion/deletion at pointers, finding insertion locations requires O(n) traversal. ArrayList is nearly always faster in practice.
Code Example Java
List<String> arrayList = new ArrayList<>(); // Fast lookup & iteration
List<String> linkedList = new LinkedList<>(); // Doubly-linked nodes
Reference: Java Collections Framework
Q 75

How does ConcurrentHashMap achieve high concurrency compared to Hashtable and Collections.synchronizedMap?

Hard
Answer
Hashtable and Collections.synchronizedMap lock the entire table on every operation. ConcurrentHashMap uses lock striping with CAS (Compare-And-Swap) for insertions and synchronized locks on individual bucket head nodes, allowing concurrent reads and writes.
Explanation
Reads in ConcurrentHashMap do not lock at all, making read throughput extremely high in multi-threaded applications.
Code Example Java
ConcurrentMap<String, Integer> map = new ConcurrentHashMap<>();
// Thread-safe atomic update operation
map.compute("counter", (k, v) -> (v == null) ? 1 : v + 1);
Reference: Java Collections Framework
Q 76

What is the contract between equals() and hashCode() in Java Collections?

Easy
Answer
If two objects are equal according to equals(), they MUST have the same hashCode(). If two objects have the same hashCode(), they are not required to be equal (hash collision).
Explanation
Violating this contract causes hash-based collections (HashMap, HashSet) to place equal objects in different buckets, breaking lookups and duplicate checks.
Code Example Java
@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (!(o instanceof Person p)) return false;
    return id == p.id && Objects.equals(name, p.name);
}

@Override
public int hashCode() {
    return Objects.hash(id, name);
}
Reference: Java Collections Framework
Q 77

Why is String or Integer commonly used as HashMap keys, and what happens if a key is mutable?

Medium
Answer
String and Integer are immutable and cache their hashCode, ensuring consistent bucket placement. If a mutable key's state changes after insertion, its hashCode changes, making the entry unretrievable (lost key).
Explanation
Always prefer immutable objects or record classes as map keys to prevent accidental bucket position mismatch.
Code Example Java
class MutableKey {
    int val;
    MutableKey(int val) { this.val = val; }
    public int hashCode() { return val; }
}

MutableKey key = new MutableKey(10);
Map<MutableKey, String> map = new HashMap<>();
map.put(key, "Data");
key.val = 20; // Mutates hash code!
System.out.println(map.get(key)); // Returns null (lost entry)
Reference: Java Collections Framework
Q 78

How does HashMap handle key collisions, and what is treeification in Java 8?

Hard
Answer
HashMap places colliding entries in the same array bucket using a linked list. In Java 8+, if a bucket's linked list length reaches TREEIFY_THRESHOLD (8) and total map capacity is at least 64, the linked list converts into a Red-Black Tree, reducing lookup complexity from O(n) to O(log n).
Explanation
If total capacity is under 64, HashMap resizes array capacity first instead of treeifying. If tree nodes decrease to UNTREEIFY_THRESHOLD (6) during removal, it converts back to a linked list.
Code Example Java
Map<BadHashKey, String> map = new HashMap<>();
// When 8 keys result in the exact same bucket index, the bucket treeifies
for (int i = 0; i < 10; i++) {
    map.put(new BadHashKey(i), "Value" + i);
}
Reference: Java Collections Framework
Q 79

What is the difference between fail-fast and fail-safe iterators, and how is ConcurrentModificationException triggered?

Hard
Answer
Fail-fast iterators (e.g., ArrayList, HashMap) check an internal modCount variable and throw ConcurrentModificationException immediately if structural changes occur during iteration. Fail-safe iterators (e.g., CopyOnWriteArrayList, ConcurrentHashMap) iterate over a snapshot copy or weakly-consistent view without throwing exceptions.
Explanation
Modifying a collection via Iterator.remove() updates modCount appropriately, avoiding exception triggers. Modifying directly via the collection object while iterating breaks the invariant.
Code Example Java
List<String> list = new ArrayList<>(List.of("A", "B"));
// Triggers ConcurrentModificationException:
for (String item : list) {
    if (item.equals("A")) list.remove(item);
}

// Safe approach using Iterator:
Iterator<String> it = list.iterator();
while (it.hasNext()) {
    if (it.next().equals("A")) it.remove();
}
Reference: Java Collections Framework

About This Topic

Prepare for Collections interviews with important concepts and commonly asked questions.