Careeroza
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, ConcurrentHashMapArrayList vs LinkedList?
| ArrayList | LinkedList | |
|---|---|---|
| Structure | dynamic array | doubly linked list |
| get(i) | O(1) | O(n) |
| add at end | amortised O(1) | O(1) |
| insert/remove in middle | O(n) (shifting) | O(1) once the node is found, finding it is O(n) |
| Memory | compact | extra prev/next pointers per element |
Tip: In practice ArrayList is the default choice; use ArrayDeque for queue/stack needs.
How does HashMap work internally?
- HashMap keeps an array of buckets (default capacity 16, load factor 0.75).
put(k, v)computesk.hashCode(), spreads the bits, and picks bucket(n - 1) & hash.- If the bucket has entries (a collision), it walks them using
equals(): same key → replace value, else append. - 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).
- 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, thena.hashCode() == b.hashCode()must be true. - Equal hash codes do not imply equal objects (collisions are allowed).
- If you override
equals(), always overridehashCode(); 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?
| HashMap | Hashtable | ConcurrentHashMap | |
|---|---|---|---|
| Thread-safe | no | yes (every method synchronized) | yes (CAS + per-bin locking) |
| null key/value | one null key, null values | not allowed | not allowed |
| Performance | fastest (single thread) | slow, one lock | high concurrency |
| Iterator | fail-fast | enumerator / fail-fast | weakly consistent (no exception) |
HashMap vs LinkedHashMap vs TreeMap?
| HashMap | LinkedHashMap | TreeMap | |
|---|---|---|---|
| Order | none | insertion (or access order) | sorted by key |
| get/put | O(1) | O(1) | O(log n) |
| Implementation | hash table | hash table + linked list | red-black tree |
| null key | allowed | allowed | not 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?
| Comparable | Comparator | |
|---|---|---|
| Package | java.lang | java.util |
| Method | compareTo(T o) | compare(T a, T b) |
| Where | inside the class (natural order) | separate object, many orders possible |
| Example | String, Integer | Comparator.comparing(Emp::salary).reversed() |