Collections Interview Questions

Explain the Collection framework hierarchy.

Iterable
  └── Collection
        ├── List   → ArrayList, LinkedList, Vector
        ├── Set    → HashSet, LinkedHashSet, TreeSet (SortedSet)
        └── Queue  → PriorityQueue, Deque → ArrayDeque, LinkedList

Map (separate hierarchy) → HashMap, LinkedHashMap, TreeMap, Hashtable, ConcurrentHashMap

ArrayList vs LinkedList?

ArrayListLinkedList
Structuredynamic arraydoubly linked list
get(i)O(1)O(n)
add at endamortised O(1)O(1)
insert/remove in middleO(n) (shifting)O(1) once the node is found, finding it is O(n)
Memorycompactextra prev/next pointers per element

Tip: In practice ArrayList is the default choice; use ArrayDeque for queue/stack needs.

How does HashMap work internally?

  1. HashMap keeps an array of buckets (default capacity 16, load factor 0.75).
  2. put(k, v) computes k.hashCode(), spreads the bits, and picks bucket (n - 1) & hash.
  3. If the bucket has entries (a collision), it walks them using equals(): same key → replace value, else append.
  4. Since Java 8, a bucket with more than 8 entries (and table ≥ 64) becomes a red-black tree, so worst case is O(log n) instead of O(n).
  5. When size exceeds capacity × load factor, the table doubles and entries are redistributed (rehashing).

What is the hashCode() and equals() contract?

  • If a.equals(b) is true, then a.hashCode() == b.hashCode() must be true.
  • Equal hash codes do not imply equal objects (collisions are allowed).
  • If you override equals(), always override hashCode(); otherwise HashMap/HashSet will not find your objects.

Example

Without hashCode(), two "equal" employees land in different buckets.

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Set<BadEmp> bad = new HashSet<>();
        bad.add(new BadEmp(1));
        bad.add(new BadEmp(1));
        System.out.println("Without hashCode: " + bad.size());

        Set<GoodEmp> good = new HashSet<>();
        good.add(new GoodEmp(1));
        good.add(new GoodEmp(1));
        System.out.println("With hashCode:    " + good.size());
    }
}

class BadEmp {
    int id;
    BadEmp(int id) { this.id = id; }
    @Override public boolean equals(Object o) { return o instanceof BadEmp e && e.id == id; }
}

class GoodEmp {
    int id;
    GoodEmp(int id) { this.id = id; }
    @Override public boolean equals(Object o) { return o instanceof GoodEmp e && e.id == id; }
    @Override public int hashCode() { return Objects.hash(id); }
}

Output

Without hashCode: 2
With hashCode:    1

HashMap vs Hashtable vs ConcurrentHashMap?

HashMapHashtableConcurrentHashMap
Thread-safenoyes (every method synchronized)yes (CAS + per-bin locking)
null key/valueone null key, null valuesnot allowednot allowed
Performancefastest (single thread)slow, one lockhigh concurrency
Iteratorfail-fastenumerator / fail-fastweakly consistent (no exception)

HashMap vs LinkedHashMap vs TreeMap?

HashMapLinkedHashMapTreeMap
Ordernoneinsertion (or access order)sorted by key
get/putO(1)O(1)O(log n)
Implementationhash tablehash table + linked listred-black tree
null keyallowedallowednot allowed (natural order)

What is the difference between fail-fast and fail-safe iterators?

A fail-fast iterator (ArrayList, HashMap) throws ConcurrentModificationException if the collection is structurally modified during iteration (it checks a modCount). A fail-safe / weakly consistent iterator (CopyOnWriteArrayList, ConcurrentHashMap) works on a snapshot or tolerates changes and never throws.

Example

Use removeIf or Iterator.remove() instead of removing inside a for-each.

import java.util.*;

public class Main {
    public static void main(String[] args) {
        List<Integer> nums = new ArrayList<>(List.of(1, 2, 3, 4, 5, 6));
        try {
            for (Integer n : nums) {
                if (n % 2 == 0) nums.remove(n);
            }
        } catch (ConcurrentModificationException e) {
            System.out.println("Caught: " + e.getClass().getSimpleName());
        }
        nums = new ArrayList<>(List.of(1, 2, 3, 4, 5, 6));
        nums.removeIf(n -> n % 2 == 0);
        System.out.println("After removeIf: " + nums);
    }
}

Output

Caught: ConcurrentModificationException
After removeIf: [1, 3, 5]

Comparable vs Comparator?

ComparableComparator
Packagejava.langjava.util
MethodcompareTo(T o)compare(T a, T b)
Whereinside the class (natural order)separate object, many orders possible
ExampleString, IntegerComparator.comparing(Emp::salary).reversed()