The Java Collections Framework provides type-safe data structures via generics — List (ArrayList for O(1) random access), Map (HashMap for O(1) average lookup), Set (HashSet for O(1) membership), and Queue/Deque — all with documented complexity guarantees and a Stream API for functional pipelines.
Java Collections give you the right data structure for every job — List for ordered sequences, Set for unique values, Map for key-value pairs — all backed by well-understood algorithms with documented Big O characteristics.
List
import java.util.*;
// ArrayList — dynamic array. O(1) get by index, O(1) amortised add
List<String> names = new ArrayList<>();
names.add("Priya");
names.add("Rahul");
names.add("Anita");
names.get(0); // "Priya"
names.size(); // 3
names.contains("Rahul"); // true
names.remove("Rahul"); // removes first occurrence
// Iterate
for (String name : names) System.out.println(name);
// Immutable list (Java 9+)
List<String> fixed = List.of("a", "b", "c"); // throws on add/remove
// LinkedList — O(1) add/remove at head/tail, O(n) get by index
LinkedList<Integer> queue = new LinkedList<>();
queue.addFirst(1);
queue.addLast(2);
queue.removeFirst(); // deque operations
// Sort
Collections.sort(names);
names.sort(Comparator.naturalOrder());
names.sort(Comparator.comparingInt(String::length).reversed());Map
// HashMap — O(1) average get/put, no guaranteed order
Map<String, Integer> scores = new HashMap<>();
scores.put("Priya", 95);
scores.put("Rahul", 88);
scores.get("Priya"); // 95
scores.getOrDefault("Zara", 0); // 0 — no KeyError
scores.containsKey("Rahul"); // true
scores.putIfAbsent("Anita", 72);
scores.computeIfAbsent("Zara", k -> 0); // atomic
// Iterate entries
for (Map.Entry<String, Integer> entry : scores.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
// LinkedHashMap — insertion-ordered
Map<String, Integer> ordered = new LinkedHashMap<>();
// TreeMap — sorted by key, O(log n)
Map<String, Integer> sorted = new TreeMap<>();
// Immutable (Java 9+)
Map<String, Integer> fixed = Map.of("a", 1, "b", 2);
Map<String, Integer> big = Map.ofEntries(
Map.entry("Priya", 95),
Map.entry("Rahul", 88)
);Set, Queue, and choosing
// HashSet — O(1) add/contains/remove, no order
Set<String> visited = new HashSet<>();
visited.add("page1");
visited.contains("page1"); // true
// TreeSet — sorted, O(log n)
Set<Integer> primes = new TreeSet<>(List.of(2, 3, 5, 7, 11));
// PriorityQueue — min-heap by default
PriorityQueue<Integer> pq = new PriorityQueue<>();
pq.offer(5); pq.offer(1); pq.offer(3);
pq.poll(); // 1 — always removes smallest
// ArrayDeque — stack and queue in one (prefer over Stack and LinkedList)
ArrayDeque<String> deque = new ArrayDeque<>();
deque.push("a"); // stack push
deque.pop(); // stack pop
deque.offer("b"); // queue enqueue
deque.poll(); // queue dequeueGenerics
Generics make collections type-safe: List<String> can only hold Strings — the compiler rejects attempts to add an Integer. Without generics, you'd need to cast on every get() and could get ClassCastException at runtime. Generics are erased at compile time — List<String> and List<Integer> are the same class at runtime. The type information only exists in source code and bytecode metadata.
// Generic class
public class Pair<A, B> {
private final A first;
private final B second;
public Pair(A first, B second) {
this.first = first; this.second = second;
}
public A getFirst() { return first; }
public B getSecond() { return second; }
@Override public String toString() {
return "(" + first + ", " + second + ")";
}
}
Pair<String, Integer> p = new Pair<>("Priya", 95);
// Generic method
public static <T extends Comparable<T>> T max(T a, T b) {
return a.compareTo(b) >= 0 ? a : b;
}
max(3, 7); // 7
max("apple", "banana"); // "banana"
// Wildcards
void printList(List<?> list) { // any type
list.forEach(System.out::println);
}
void addNumbers(List<? super Integer> list) { // Integer or supertype
list.add(42);
}
double sumList(List<? extends Number> list) { // Number or subtype
return list.stream().mapToDouble(Number::doubleValue).sum();
}Streams and collection pipelines
import java.util.stream.*;
List<String> names = List.of("Priya", "Rahul", "Anita", "Priya");
// Stream pipeline — lazy, functional, not modifying the original
List<String> unique = names.stream()
.distinct()
.filter(n -> n.length() > 4)
.map(String::toUpperCase)
.sorted()
.collect(Collectors.toList());
// [ANITA, PRIYA, RAHUL]
// Collectors
Map<Integer, List<String>> byLength = names.stream()
.collect(Collectors.groupingBy(String::length));
long count = names.stream().filter(n -> n.startsWith("P")).count();
Optional<String> first = names.stream().findFirst();
String joined = names.stream().collect(Collectors.joining(", "));List<String> and List<Integer> are the same class (java.util.ArrayList) at runtime. You cannot do list instanceof List<String> — the type parameter is erased. This is why you see "unchecked cast" warnings when mixing generics with reflection.list.stream().filter(...) creates a new stream pipeline — it does not filter the original list. The source is unchanged. To get a new collection, collect: .collect(Collectors.toList()).ArrayList vs LinkedList: almost always use ArrayList. Despite LinkedList's theoretical O(1) head insert, ArrayList's cache-friendly memory layout makes it faster in practice for most operations. Only use LinkedList when you frequently insert/remove from both ends and never access by index.Type erasure and heap pollution
Generic type information is erased by the Java compiler (JLS §4.6). At runtime, List<String> is just List. This was a deliberate design choice for backward compatibility with pre-generics Java code. The consequences: you cannot create generic arrays (new T[10] is illegal), you cannot use instanceof with parameterised types (x instanceof List<String>), and reflective operations work on the raw type. "Heap pollution" occurs when a variable of a parameterised type refers to an object that is not of that type — usually caused by unchecked casts and raw type usage. The @SafeVarargs annotation suppresses warnings for methods that are guaranteed not to cause heap pollution.