Java Collections
List Β· ArrayList Β· LinkedList Β· Map & HashMap Β· Set & HashSet Β· Queue Β· Iterator Β· Collections utility
Sheet 2 of 7
Java 17+
Intermediate
Printable
Collections Framework β Overview
Interface Hierarchy
// Key interfaces (java.util) Collection<E> βββ List<E> // ordered, duplicates ok βββ Set<E> // no duplicates βββ Queue<E> // FIFO processing Map<K,V> // keyβvalue pairs βββ HashMap // fast, unordered βββ LinkedHashMap // insertion order βββ TreeMap // sorted by key
Choosing the Right Type
// Need ordered + duplicates? ArrayList<String> list = new ArrayList(); // Need unique values only? HashSet<String> set = new HashSet(); // Need key β value lookup? HashMap<String,Integer> map = new HashMap(); // Need FIFO queue? Queue<String> q = new LinkedList(); // Need sorted list? TreeSet<Integer> ts = new TreeSet();
Quick Complexity Reference
// ArrayList β O(1) get, O(n) insert mid // LinkedList β O(n) get, O(1) insert ends // HashMap β O(1) avg get/put // TreeMap β O(log n) get/put // HashSet β O(1) add/contains // TreeSet β O(log n) add/contains // PriorityQ β O(log n) offer/poll // β O(1) peek
Program to interfaces: Declare variables as
List, Map, Set β not ArrayList or HashMap β so you can swap implementations freely: List<String> list = new ArrayList<>();List β ArrayList
Create & Add
import java.util.ArrayList; import java.util.List; List<String> names = new ArrayList<>(); names.add("Alice"); // append names.add(0, "Bob"); // insert at index names.addAll(List.of("Carol","Dan")); // Create with initial values (Java 9+) List<Integer> nums = new ArrayList<>( List.of(1, 2, 3, 4, 5));
Access Β· Update Β· Remove
names.get(0) // "Bob" names.set(0, "Ben") // replace index 0 names.remove(0) // remove by index names.remove("Alice") // remove by value names.size() // count names.isEmpty() // boolean names.contains("Carol") // boolean names.indexOf("Dan") // index or -1 names.clear() // remove all names.subList(1, 3) // view [1..2]
Iterate & Sort
// For-each (most common) for (String n : names) System.out.println(n); // Index loop for (int i = 0; i < names.size(); i++) { System.out.println(names.get(i)); } // Sort (natural / custom) Collections.sort(names); names.sort(Comparator.reverseOrder());
ArrayList vs LinkedList: Prefer
ArrayList in almost all cases β better cache locality and random access. Use LinkedList only when you insert/delete at both ends frequently.LinkedList β Deque Use
As a Deque (Double-Ended Queue)
import java.util.LinkedList; import java.util.Deque; Deque<String> dq = new LinkedList<>(); // Add to either end dq.addFirst("front"); dq.addLast("back"); // Peek without removing dq.peekFirst(); dq.peekLast(); // Remove from either end dq.pollFirst(); dq.pollLast();
As a Stack (LIFO)
// Use Deque as a stack Deque<Integer> stack = new LinkedList<>(); stack.push(1); // addFirst stack.push(2); stack.peek(); // 2 β top, no remove stack.pop(); // 2 β removes top // Avoid java.util.Stack (legacy) // Prefer ArrayDeque for stack needs Deque<Integer> s = new ArrayDeque<>();
Avoid legacy Stack:
java.util.Stack is synchronized and slow. Use ArrayDeque for both stack and queue operations in single-threaded code.Map β HashMap Β· LinkedHashMap Β· TreeMap
HashMap β Core Operations
import java.util.HashMap; import java.util.Map; Map<String,Integer> scores = new HashMap<>(); scores.put("Alice", 95); // add/update scores.get("Alice") // 95 scores.getOrDefault("X",0) // 0 if absent scores.containsKey("Alice") // true scores.containsValue(95) // true scores.remove("Alice") // removes key scores.size() // count scores.isEmpty() // boolean
Iterating a Map
// Entry set β most common for (Map.Entry<String,Integer> e : scores.entrySet()) { System.out.println( e.getKey() + " β " + e.getValue()); } // Keys only / values only for (String k : scores.keySet()) {} for (int v : scores.values()) {} // forEach lambda (Java 8+) scores.forEach((k, v) -> System.out.println(k + ": " + v));
Useful Map Methods (Java 8+)
// putIfAbsent β only if key missing scores.putIfAbsent("Bob", 80); // compute β update based on old value scores.compute("Alice", (k, v) -> v + 5); // merge β combine old + new scores.merge("Alice", 10, Integer::sum); // Sorted map Map<String,Integer> sorted = new TreeMap<>(scores);
Immutable maps (Java 9+):
Map.of("k1", v1, "k2", v2) creates an unmodifiable map. Use Map.copyOf(existing) to make an immutable copy. Great for lookup tables and configuration.Set β HashSet Β· TreeSet Β· LinkedHashSet
HashSet β Core Operations
import java.util.HashSet; import java.util.Set; Set<String> tags = new HashSet<>(); tags.add("java"); tags.add("java"); // ignored β duplicate tags.contains("java") // true β O(1) tags.remove("java") // removes tags.size() // count // Iterate (order not guaranteed) for (String t : tags) System.out.println(t);
Set Operations (union, intersect, diff)
Set<Integer> a = new HashSet<>(Set.of(1,2,3)); Set<Integer> b = new HashSet<>(Set.of(2,3,4)); // Union: a βͺ b Set<Integer> union = new HashSet<>(a); union.addAll(b); // {1,2,3,4} // Intersection: a β© b Set<Integer> inter = new HashSet<>(a); inter.retainAll(b); // {2,3} // Difference: a β b Set<Integer> diff = new HashSet<>(a); diff.removeAll(b); // {1}
Sorted set: Use
TreeSet to always iterate in sorted order. Use LinkedHashSet to maintain insertion order while still removing duplicates.Queue & PriorityQueue
Queue β FIFO (LinkedList)
import java.util.Queue; import java.util.LinkedList; Queue<String> q = new LinkedList<>(); q.offer("first"); // enqueue β safe q.offer("second"); q.peek(); // "first" β no remove q.poll(); // "first" β removes q.isEmpty(); // false q.size(); // 1 // prefer offer/poll/peek over // add/remove/element (no exception)
PriorityQueue β min-heap by default
import java.util.PriorityQueue; PriorityQueue<Integer> pq = new PriorityQueue<>(); pq.offer(5); pq.offer(1); pq.offer(3); pq.peek(); // 1 β smallest pq.poll(); // 1 β removes smallest // Max-heap β reverse order PriorityQueue<Integer> maxPQ = new PriorityQueue<>(Comparator.reverseOrder());
poll() vs remove():
poll() returns null if empty (safe). remove() throws NoSuchElementException. Prefer offer/poll/peek in production code.Iterator & ListIterator
Iterator β safe remove during loop
List<String> list = new ArrayList<>( List.of("a","b","c","d")); Iterator<String> it = list.iterator(); while (it.hasNext()) { String s = it.next(); if (s.equals("b")) it.remove(); // safe! } // list β ["a","c","d"]
ListIterator β bi-directional
ListIterator<String> li = list.listIterator(); while (li.hasNext()) { String s = li.next(); li.set(s.toUpperCase()); // replace } // Go backwards while (li.hasPrevious()) { System.out.println(li.previous()); }
removeIf β cleanest removal (Java 8+)
List<Integer> nums = new ArrayList<>( List.of(1,2,3,4,5)); // Remove all even numbers nums.removeIf(n -> n % 2 == 0); // [1, 3, 5] // ConcurrentModificationException! // NEVER remove inside for-each: for (Integer n : nums) nums.remove(n); // β CRASH
ConcurrentModificationException: Never call
list.remove() inside a for-each loop β use iterator.remove(), removeIf(), or collect items to remove and call removeAll() after.Collections Utility Class
import java.util.Collections; List<Integer> list = new ArrayList<>( List.of(3,1,4,1,5,9)); Collections.sort(list); // [1,1,3,4,5,9] Collections.reverse(list); // [9,5,4,3,1,1] Collections.shuffle(list); // random order Collections.min(list); // 1 Collections.max(list); // 9 Collections.frequency(list, 1); // 2 Collections.fill(list, 0); // all zeros Collections.nCopies(3, "x"); // ["x","x","x"] Collections.unmodifiableList(list); // read-only view Collections.synchronizedList(list); // thread-safe Collections.disjoint(list, other); // no common elements?
Generics with Collections
Wildcards & Bounded Types
// ? β any type (unbounded) void printAll(List<?> list) { for (Object o : list) System.out.println(o); } // ? extends T β upper bound (read) double sum(List<? extends Number> nums) { return nums.stream().mapToDouble( Number::doubleValue).sum(); } // ? super T β lower bound (write) void addNumbers(List<? super Integer> list) { list.add(1); list.add(2); }
PECS rule: Producer Extends, Consumer Super. If a collection produces (you read from it) use
<? extends T>. If it consumes (you write to it) use <? super T>.Collections Comparison Table
| Class | Interface | Ordered? | Sorted? | Duplicates? | Null key/val? | Thread-safe? | Best for |
|---|---|---|---|---|---|---|---|
| ArrayList | List | Insertion order | No | Yes | 1 null | No | Random access, iteration |
| LinkedList | List, Deque | Insertion order | No | Yes | Yes | No | Queue, stack, frequent inserts |
| HashMap | Map | No | No | Yes (values) | 1 null key | No | Fast key lookup |
| LinkedHashMap | Map | Insertion order | No | Yes (values) | 1 null key | No | LRU cache pattern |
| TreeMap | NavigableMap | Key-sorted | Yes (keys) | Yes (values) | No null key | No | Sorted map, range queries |
| HashSet | Set | No | No | No | One null | No | Unique check, dedup |
| TreeSet | NavigableSet | Sorted | Yes | No | No null | No | Sorted unique elements |
| PriorityQueue | Queue | Priority | Yes (priority) | Yes | No null | No | Min/max heap, scheduling |
| ArrayDeque | Deque | Insertion order | No | Yes | No null | No | Fast stack & queue |
Collections Mastery Checklist
| List Skills | Key point |
|---|---|
| Create & populate an ArrayList | List.of + new ArrayList |
| Access, update, remove by index | get / set / remove |
| Sort with Comparator | list.sort() |
| Know when to use LinkedList | double-ended ops |
| Map & Set Skills | Key point |
|---|---|
| Put, get, iterate a HashMap | entrySet / forEach |
| Use getOrDefault safely | no NullPointerException |
| Perform set union / intersect | addAll / retainAll |
| Pick HashMap vs TreeMap | speed vs sorted |
| Iterator & Safety | Key point |
|---|---|
| Remove during iteration safely | iterator.remove() |
| Use removeIf with lambda | cleanest approach |
| Avoid ConcurrentModification | never remove in for-each |
| Understand PECS wildcard rule | extends=read, super=write |
Next up β Sheet 3: Java Streams Β·
filter Β· map Β· reduce Β· collect Β· sorted Β· distinct Β· flatMap Β· Optional β functional-style data processing with the Streams API.