← Home
☕Java Developer Interview Questions — Fresher to 5 YOEJava Dev InterviewNEW
📦

Collections Framework

List, Set, Map, Queue internals · 30 questions

1

What is the difference between Collection and Collections?

Must Know🌱 Fresher

Collection (singular) is the root interface of the framework —List, Set, and Queue all extend it, describing "a group of objects." Collections (plural) is a utility class of static helper methods that operate on collections — Collections.sort(list), Collections.unmodifiableList(list), Collections.synchronizedMap(map), etc. (Same naming pattern as Arrays being the utility class for arrays.)

Collections
2

Can you sketch the Java Collections Framework hierarchy?

Must Know🌱 Fresher
🌳 Java Collections Framework — top-level shape
Iterable
  └── Collection
        ├── List        (ordered, duplicates allowed)   -> ArrayList, LinkedList, Vector
        ├── Set          (no duplicates)                 -> HashSet, LinkedHashSet, TreeSet (SortedSet)
        └── Queue        (FIFO / priority ordering)       -> ArrayDeque, PriorityQueue, LinkedList
              └── Deque   (double-ended queue)             -> ArrayDeque

Map (separate hierarchy -- NOT a Collection)
  └── HashMap, LinkedHashMap, TreeMap (SortedMap), Hashtable, ConcurrentHashMap
Collections
3

What is the difference between ArrayList and LinkedList?

Must Know🌱 Fresher
📐 ArrayList — contiguous backing array
[ a | b | c | d | _ | _ ]
index:  0   1   2   3
get(2) -> O(1) direct index
insert at 1 -> shift c,d right -> O(n)
🔗 LinkedList — doubly-linked nodes
[a] <-> [b] <-> [c] <-> [d]
get(2) -> walk from head/tail -> O(n)
insert after node b -> relink pointers -> O(1) once positioned
ArrayListLinkedList
Backing structureResizable arrayDoubly-linked list of nodes
Random access get(i)O(1)O(n)
Insert/remove at endsAmortized O(1) at tail, O(n) at headO(1)
Insert/remove in middleO(n) (shifts elements)O(n) to find + O(1) to relink
Memory overheadLower (just the array + some slack)Higher (two pointers + object header per node)

In practice, ArrayList wins almost always — cache locality makes even its "O(n) shift" faster in the real world than LinkedList's pointer chasing for most workloads.

ListArrayListLinkedList
4

How does HashMap work internally?

Must Know📊 Mid

A HashMap stores entries in an array of buckets. To put a key/value: compute key.hashCode(), run it through a supplemental "hash spreading" step to reduce collisions from poor hash functions, then take hash & (capacity - 1) to pick a bucket index. If that bucket is empty, the entry goes straight in; if not, it's chained onto the existing entries in that bucket (checking equals() to detect an existing key vs a genuine collision).

🪣 HashMap bucket array
table[0] -> (empty)
table[1] -> ["a" -> 1] -> ["k" -> 9]   (collision: both hash to bucket 1, chained)
table[2] -> ["b" -> 2]
table[3] -> (empty)

get("k"): hash("k") -> bucket 1 -> walk chain, equals("k") match -> return 9

get(key) follows the same path: hash → bucket → walk the chain comparing with equals() until it finds a match (or falls off the end → null).

HashMapMap
5

What is the difference between HashMap, Hashtable, and ConcurrentHashMap?

Must Know📊 Mid
HashMapHashtableConcurrentHashMap
Thread-safe?NoYes (every method synchronized)Yes (fine-grained, lock-free reads)
Null key/value1 null key, many null valuesNone allowedNone allowed
Performance under contentionN/A (not safe to share)Poor — one lock for the whole mapGood — locks only affect the bins being written
EraModern defaultLegacy (JDK 1.0)Modern concurrent default

Rule of thumb: single-threaded or externally-synchronized access → HashMap; shared across threads → ConcurrentHashMap, never Hashtable (legacy, strictly worse). See the deep dive on HashMap vs ConcurrentHashMap internals → for how CHM achieves lock-free reads.

HashMapConcurrency
6

What is the difference between HashMap, LinkedHashMap, and TreeMap?

Must Know🌱 Fresher
HashMapLinkedHashMapTreeMap
Iteration orderNo guaranteed orderInsertion order (or access order, configurable)Sorted by key (natural or Comparator)
Backing structureBucket arrayBucket array + doubly-linked list threading entriesRed-black tree
get/putO(1) averageO(1) averageO(log n)
Use whenOrder doesn't matterNeed predictable iteration (or an LRU cache)Need sorted keys / range queries
Map
7

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

Must Know📊 Mid

Fail-fast iterators (the default for ArrayList, HashMap, HashSet, etc.) detect structural modification during iteration via an internal modCount counter — if the collection changes while you're iterating (other than through the iterator's own remove()), the next next() call throws ConcurrentModificationException. It's a best-effort bug detector, not a guarantee.

Fail-safe iterators (e.g. CopyOnWriteArrayList, ConcurrentHashMap) iterate over a stable snapshot (or a structure designed so concurrent writes don't corrupt an in-progress read), so they never throw — but they may not reflect modifications made after the iterator was created.

IteratorCollections
8

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

Must Know🌱 Fresher
HashSetLinkedHashSetTreeSet
OrderNo guaranteed orderInsertion orderSorted order
add/containsO(1) averageO(1) averageO(log n)
Backed byHashMapLinkedHashMapTreeMap
Set
9

What is the difference between Comparable and Comparator?

Must Know🌱 Fresher
ComparableComparator
Where definedInside the class itself (compareTo)External, separate class/lambda (compare)
How many orderings?One — the class's single "natural" orderingMany — define as many comparators as you need
Use whenThe class has one obvious natural order (e.g. numbers ascending)You need custom/alternate/multiple orderings without modifying the class
Comparator with method references (common in interviews)java
list.sort(Comparator.comparing(Person::getLastName)
                     .thenComparing(Person::getFirstName));
Sorting
10

What is the difference between an array and an ArrayList?

Must Know🌱 Fresher
ArrayArrayList
SizeFixed at creationGrows dynamically
PrimitivesCan hold primitives directly (int[])Only objects — primitives get autoboxed (Integer)
TypeCan be primitive or generic-freeGeneric, type-checked at compile time
Utility methodsMinimal — Arrays helper classRich API (add, remove, contains, streams...)
ArrayArrayList
11

How does ArrayList grow internally when it runs out of capacity?

Important📊 Mid

Internally, ArrayList holds an Object[]. When add() would exceed the array's length, it allocates a new array — by default 1.5× the old capacity (oldCapacity + (oldCapacity >> 1)) — copies every element over with Arrays.copyOf, and the old array becomes garbage. This makes a single add() occasionally O(n), but amortized O(1) across many additions, since resizes become exponentially rarer.

If you know the approximate final size upfront, pass it to the constructor (new ArrayList<>(1000)) to avoid repeated resize-and-copy churn.

ListArrayList
12

What happens when two keys collide in a HashMap?

Important📊 Mid

Two keys with different content can hash to the same bucket (a collision) — HashMap handles this by chaining: all entries that land in the same bucket are linked together (a list, or a red-black tree once the chain gets long — see the treeification question). On lookup, HashMap walks that bucket's chain and uses each candidate key's equals() to find the actual match, since a shared bucket doesn't necessarily mean the keys are equal.

HashMap
13

What is load factor and rehashing in HashMap?

Important📊 Mid

Load factor (default 0.75) is the fraction full a HashMap can get before it resizes: threshold = capacity × loadFactor. Once size exceeds that threshold, the map rehashes — it doubles the bucket array's capacity and re-distributes every existing entry into the new, larger array (since the bucket index formula depends on capacity, old bucket assignments are no longer valid).

A lower load factor means more buckets (faster average lookups, more wasted memory); a higher load factor packs more into fewer buckets (less memory, more collisions/chaining). 0.75 is a measured middle ground the JDK authors chose as a good general-purpose default.

HashMap
14

What causes ConcurrentModificationException, and how do you avoid it?

Important🌱 Fresher

It's thrown when you structurally modify a fail-fast collection (add/remove an element) while iterating over it with a for-each loop or an Iterator whose modCount snapshot no longer matches — most commonly, calling list.remove(x) directly inside a for (String s : list) loop.

Fix: use the iterator's own remove()throws CMEjava
for (String s : list) {
    if (s.isEmpty()) list.remove(s); // modifies the list mid-iteration
}
Correct approachessafejava
Iterator<String> it = list.iterator();
while (it.hasNext()) {
    if (it.next().isEmpty()) it.remove(); // iterator tracks its own modCount
}
// or, since Java 8:
list.removeIf(String::isEmpty);
IteratorExceptions
15

How is HashSet implemented internally?

Important📊 Mid

HashSet is a thin wrapper around a HashMap: every element you add becomes a key in an internal map, mapped to a shared dummy constant value. Set semantics (no duplicates, O(1) contains) fall straight out of Map key semantics — you get them for free.

Roughly how HashSet.add() worksjava
private static final Object PRESENT = new Object();
private transient HashMap<E, Object> map = new HashMap<>();

public boolean add(E e) {
    return map.put(e, PRESENT) == null; // true if e wasn't already a key
}
SetHashMap
16

How is PriorityQueue implemented internally?

Important📊 Mid

PriorityQueue is backed by a binary heap stored in a plain array (a min-heap by default — smallest element via compareTo/Comparator always at the root/index 0). offer() appends at the end then "bubbles up" to restore the heap property; poll() removes the root, moves the last element to the root, and "sifts down" — both O(log n). It gives O(1) peek at the minimum, which is the whole point of a priority queue: cheap access to "what's next," not full sorted iteration order.

QueueHeap
17

Why is ArrayDeque preferred over the legacy Stack class?

Important📊 Mid

The legacy Stack class extends Vector — it inherits a pile of irrelevant list methods (get(i), insertElementAt...) that let code violate stack discipline, and every method is synchronized even in single-threaded use, adding pure overhead. ArrayDeque implements Deque and gives you push/pop/peek with array-backed performance and no synchronization tax — the JDK docs themselves recommend it over Stack.

DequeStack
18

What is the difference between Iterator and ListIterator?

Important🌱 Fresher
IteratorListIterator
DirectionForward onlyForward and backward
Available onAny CollectionOnly List implementations
Modificationremove() onlyremove(), set(), and add()
Index accessNoYes — nextIndex()/previousIndex()
IteratorList
19

How do you create immutable collections in Java, and what happens if you try to modify one?

Important📊 Mid

Java 9 added List.of(...), Set.of(...), and Map.of(...) factory methods that return genuinely immutable collections. The older approach, Collections.unmodifiableList(list), only wraps an existing mutable list — the wrapper itself rejects modifications, but the underlying list can still be changed through the original reference (and those changes show through the wrapper).

Modifying an immutable collectionjava
List<Integer> nums = List.of(1, 2, 3);
nums.add(4); // throws UnsupportedOperationException
CollectionsJava 9
20

How do you sort a list of custom objects in Java?

Important🌱 Fresher

Two options: make the class implement Comparable<T> for one natural ordering, or pass a Comparator<T> (often a lambda or method reference) when you need a different/custom order without touching the class.

Both approachesjava
// Natural ordering
class Employee implements Comparable<Employee> {
    int salary;
    public int compareTo(Employee o) { return Integer.compare(salary, o.salary); }
}
Collections.sort(employees); // uses compareTo

// Custom ordering, no change to Employee needed
employees.sort(Comparator.comparingInt((Employee e) -> e.salary).reversed());
Sorting
21

What is the difference between Queue and Deque?

Important🌱 Fresher

Queue is FIFO — you add at the tail (offer) and remove from the head (poll). Deque ("double-ended queue") extends that to allow adding/removing at both ends, so it can act as a FIFO queue, a LIFO stack, or both at once — which is why ArrayDeque is the modern replacement for both LinkedList-as-a-queue and the legacy Stack class.

QueueDeque
22

Does HashMap allow null keys and values? What about Hashtable?

Important📊 Mid

HashMap allows exactly one null key (stored in bucket 0, since there's no hash to compute) and any number of null values. Hashtable (and ConcurrentHashMap) allow neither — they throw NullPointerException on a null key or value, largely because in a concurrent map, a null return from get() would be ambiguous: does it mean "key not present" or "key present with a null value"? Disallowing null sidesteps that ambiguity entirely.

HashMap
23

What is HashMap treeification (Java 8) and when does it kick in?

Advanced📊 Mid

Before Java 8, every bucket was a simple linked list, so a bucket with many collisions degraded lookups in that bucket to O(n) — an attacker who knows your hash function could deliberately craft keys that all collide, DoS-ing the map. Since Java 8, when a single bucket's chain grows past 8 entries (and the table has at least 64 buckets), that bucket is converted from a linked list into a red-black tree, dropping worst-case lookup within that bucket to O(log n). If the bucket later shrinks below 6 entries (e.g. after removals), it's converted back to a plain list — the treeify/untreeify thresholds have a small gap (8 vs 6) to avoid thrashing back and forth at the boundary.

HashMapJava 8
24

What is CopyOnWriteArrayList, and when should you use it?

Advanced📊 Mid

CopyOnWriteArrayList makes a fresh copy of its entire backing array on every write (add/remove/set), then swaps the reference atomically — readers always see a stable, never-changing snapshot without any locking, which makes iteration exception-free even if writers are active concurrently. This is excellent when reads vastly outnumber writes (e.g. a list of event listeners that's iterated constantly but modified rarely) and terrible when writes are frequent, since each write is O(n) to copy the whole array.

ConcurrencyList
25

What is WeakHashMap and when would you use it?

Advanced📊 Mid

WeakHashMap holds its keys via weak references — if a key has no other strong references anywhere in the program, the garbage collector is free to reclaim it, and its entry is automatically removed from the map. It's useful for caches/metadata tables keyed by an object you don't otherwise own the lifecycle of, so entries don't leak memory forever just because they're sitting in your map. See the WeakHashMap deep dive → for the reference-queue mechanics and gotchas (don't use it if you need entries to survive as long as the map does).

MapGC
26

What is HashMap’s default initial capacity and load factor, and why 0.75?

Advanced📊 Mid

Default initial capacity is 16 buckets, default load factor is 0.75 (resize threshold = 12). Capacities are always kept a power of two so that hash & (capacity - 1) is a fast bitmask operation equivalent to hash % capacity, avoiding a slower modulo. 0.75 was chosen by the JDK authors as an empirically reasonable time/space trade-off — low enough to keep the average chain length short (good lookup speed), high enough to not waste large amounts of memory on mostly-empty buckets.

HashMap
27

How would you use LinkedHashMap to build a simple LRU cache?

Advanced📊 Mid

Construct a LinkedHashMap with accessOrder = true so it re-orders its internal linked list on every get/put, moving the touched entry to the end (most-recently-used) — the head of the list naturally becomes the least-recently-used entry. Override removeEldestEntry to evict it once the map grows past your capacity, and you have a working LRU cache in a handful of lines.

LRU cache via LinkedHashMapjava
class LruCache<K, V> extends LinkedHashMap<K, V> {
    private final int capacity;
    LruCache(int capacity) {
        super(16, 0.75f, true); // accessOrder = true
        this.capacity = capacity;
    }
    protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
        return size() > capacity; // evict LRU once over capacity
    }
}
MapLRU
28

Why are Vector and Stack considered legacy classes?

Optional🌱 Fresher

Both predate the Collections Framework (JDK 1.0) and synchronize every method by default — which is nearly always the wrong default: single-threaded code pays needless lock overhead, and multi-threaded code usually needs more than method-level locking anyway (e.g. an atomic check-then-act across multiple calls). Modern code uses ArrayList instead of Vector, and ArrayDeque instead of Stack; for genuine concurrent needs, Collections.synchronizedList(...) or classes from java.util.concurrent are preferred.

Legacy
29

What do NavigableMap and NavigableSet add over TreeMap/TreeSet?

Optional📊 Mid

NavigableMap/NavigableSet (implemented by TreeMap/TreeSet) add relative-position lookups on top of a sorted structure: floorKey/floorEntry (largest ≤ given key), ceilingKey (smallest ≥), lowerKey (strictly <), higherKey (strictly >), plus headMap/tailMap/subMap range views and descendingMap for reverse iteration — handy for range queries like "the closest booking slot at or after 3pm."

MapSet
30

What are EnumMap and EnumSet, and why use them over HashMap/HashSet for enum keys?

Optional📊 Mid

Both are specialized, highly efficient implementations for enum keys/elements — EnumMap stores values in a plain array indexed by each enum constant's ordinal() instead of hashing, and EnumSet is backed by a bitmask (a single long for enums with ≤ 64 constants). Both are faster and far more memory-efficient than HashMap/HashSet for enum keys, and EnumMap iterates in the enum's natural declaration order for free.

EnumMapSet