
Java’s Collections Framework provides data structures for storing and manipulating groups of objects. This cheat sheet covers the interfaces, implementations, and operations you’ll use most often.
Collection Hierarchy
Iterable
|
Collection
|
+-- List (ordered, allows duplicates)
| +-- ArrayList
| +-- LinkedList
| +-- Vector
|
+-- Set (no duplicates)
| +-- HashSet
| +-- LinkedHashSet
| +-- TreeSet
|
+-- Queue (FIFO ordering)
+-- LinkedList
+-- PriorityQueue
+-- ArrayDeque
Map (key-value pairs, separate hierarchy)
+-- HashMap
+-- LinkedHashMap
+-- TreeMap
+-- Hashtable
When to Use What
| Need | Use | Why |
|---|---|---|
| Fast random access by index | ArrayList | O(1) get/set by index |
| Fast insertion/deletion at ends | LinkedList or ArrayDeque | O(1) add/remove at head/tail |
| No duplicates, fast lookup | HashSet | O(1) contains/add/remove |
| No duplicates, sorted order | TreeSet | O(log n) operations, sorted |
| No duplicates, insertion order | LinkedHashSet | O(1) operations, maintains order |
| Key-value pairs, fast lookup | HashMap | O(1) get/put by key |
| Key-value pairs, sorted keys | TreeMap | O(log n) operations, sorted keys |
| Key-value pairs, insertion order | LinkedHashMap | O(1) operations, maintains order |
| FIFO queue | ArrayDeque or LinkedList | O(1) enqueue/dequeue |
| Priority queue | PriorityQueue | O(log n) insert, O(1) peek min |
| Stack (LIFO) | ArrayDeque | O(1) push/pop |
| Thread-safe map | ConcurrentHashMap | Concurrent access without full locking |
List Operations
ArrayList
// Creation
List<String> list = new ArrayList<>();
List<String> list = new ArrayList<>(Arrays.asList("a", "b", "c"));
List<String> list = new ArrayList<>(100); // Initial capacity
// Adding elements
list.add("item"); // Add to end
list.add(0, "first"); // Add at index
list.addAll(otherList); // Add all from another collection
// Accessing elements
String item = list.get(0); // Get by index
int index = list.indexOf("item"); // First occurrence (-1 if not found)
int last = list.lastIndexOf("item"); // Last occurrence
// Modifying
list.set(0, "newValue"); // Replace at index
list.remove(0); // Remove by index
list.remove("item"); // Remove first occurrence
list.clear(); // Remove all
// Querying
int size = list.size();
boolean empty = list.isEmpty();
boolean has = list.contains("item");
// Converting
String[] array = list.toArray(new String[0]);
Object[] objects = list.toArray();
// Iterating
for (String s : list) { }
list.forEach(s -> System.out.println(s));
for (int i = 0; i < list.size(); i++) { }
// Sorting
Collections.sort(list); // Natural order
Collections.sort(list, Comparator.reverseOrder());
list.sort(Comparator.comparing(String::length));
LinkedList
Same List methods plus Deque operations:
LinkedList<String> linked = new LinkedList<>();
// Deque operations (fast at both ends)
linked.addFirst("first");
linked.addLast("last");
linked.removeFirst();
linked.removeLast();
String first = linked.getFirst();
String last = linked.getLast();
String peeked = linked.peek(); // Returns null if empty
String polled = linked.poll(); // Removes and returns head
Set Operations
HashSet
// Creation
Set<String> set = new HashSet<>();
Set<String> set = new HashSet<>(Arrays.asList("a", "b", "c"));
Set<String> set = new HashSet<>(list); // From any collection
// Basic operations
set.add("item"); // Returns false if already present
set.remove("item");
set.contains("item");
set.size();
set.isEmpty();
set.clear();
// Bulk operations
set.addAll(otherSet); // Union
set.retainAll(otherSet); // Intersection
set.removeAll(otherSet); // Difference
// Iterating (no guaranteed order for HashSet)
for (String s : set) { }
set.forEach(System.out::println);
TreeSet
Sorted set with navigation methods:
TreeSet<Integer> tree = new TreeSet<>();
tree.addAll(Arrays.asList(5, 2, 8, 1, 9));
// Navigation
Integer first = tree.first(); // 1 (smallest)
Integer last = tree.last(); // 9 (largest)
Integer lower = tree.lower(5); // 2 (largest element < 5)
Integer higher = tree.higher(5); // 8 (smallest element > 5)
Integer floor = tree.floor(5); // 5 (largest element <= 5)
Integer ceiling = tree.ceiling(5); // 5 (smallest element >= 5)
// Range views
SortedSet<Integer> head = tree.headSet(5); // Elements < 5
SortedSet<Integer> tail = tree.tailSet(5); // Elements >= 5
SortedSet<Integer> sub = tree.subSet(2, 8); // 2 <= elements < 8
// Reverse order
NavigableSet<Integer> desc = tree.descendingSet();
Map Operations
HashMap
// Creation
Map<String, Integer> map = new HashMap<>();
Map<String, Integer> map = new HashMap<>(Map.of("a", 1, "b", 2));
// Adding/updating
map.put("key", 100); // Add or replace
map.putIfAbsent("key", 100); // Add only if missing
map.putAll(otherMap); // Add all from another map
// Accessing
Integer value = map.get("key"); // null if not found
Integer value = map.getOrDefault("key", 0); // Default if not found
boolean hasKey = map.containsKey("key");
boolean hasVal = map.containsValue(100);
// Removing
map.remove("key"); // Remove by key
map.remove("key", 100); // Remove only if value matches
// Size
int size = map.size();
boolean empty = map.isEmpty();
map.clear();
// Iterating
for (String key : map.keySet()) { }
for (Integer value : map.values()) { }
for (Map.Entry<String, Integer> entry : map.entrySet()) {
String k = entry.getKey();
Integer v = entry.getValue();
}
map.forEach((k, v) -> System.out.println(k + ": " + v));
// Compute operations
map.compute("key", (k, v) -> v == null ? 1 : v + 1);
map.computeIfAbsent("key", k -> expensiveOperation());
map.computeIfPresent("key", (k, v) -> v * 2);
map.merge("key", 1, Integer::sum); // Add 1 or increment
TreeMap
Sorted map with navigation:
TreeMap<String, Integer> tree = new TreeMap<>();
// Navigation (similar to TreeSet)
String firstKey = tree.firstKey();
String lastKey = tree.lastKey();
Map.Entry<String, Integer> first = tree.firstEntry();
Map.Entry<String, Integer> last = tree.lastEntry();
// Range views
SortedMap<String, Integer> head = tree.headMap("m");
SortedMap<String, Integer> tail = tree.tailMap("m");
SortedMap<String, Integer> sub = tree.subMap("a", "m");
Queue and Deque Operations
Queue (FIFO)
Queue<String> queue = new LinkedList<>();
// Or: Queue<String> queue = new ArrayDeque<>();
// Adding (to tail)
queue.add("item"); // Throws exception if full
queue.offer("item"); // Returns false if full
// Accessing head
String head = queue.element(); // Throws exception if empty
String head = queue.peek(); // Returns null if empty
// Removing head
String removed = queue.remove(); // Throws exception if empty
String removed = queue.poll(); // Returns null if empty
Deque (Double-ended Queue)
Deque<String> deque = new ArrayDeque<>();
// Add to front/back
deque.addFirst("front");
deque.addLast("back");
deque.offerFirst("front");
deque.offerLast("back");
// Access front/back
String first = deque.getFirst();
String last = deque.getLast();
String first = deque.peekFirst();
String last = deque.peekLast();
// Remove from front/back
String removed = deque.removeFirst();
String removed = deque.removeLast();
String removed = deque.pollFirst();
String removed = deque.pollLast();
Stack Operations (use Deque)
Deque<String> stack = new ArrayDeque<>();
stack.push("item"); // Add to top
String top = stack.peek(); // View top without removing
String popped = stack.pop(); // Remove and return top
PriorityQueue
// Min-heap by default (smallest first)
PriorityQueue<Integer> minHeap = new PriorityQueue<>();
// Max-heap
PriorityQueue<Integer> maxHeap = new PriorityQueue<>(Comparator.reverseOrder());
// Custom ordering
PriorityQueue<String> byLength = new PriorityQueue<>(
Comparator.comparingInt(String::length)
);
minHeap.add(5);
minHeap.add(2);
minHeap.add(8);
int smallest = minHeap.peek(); // 2 (doesn't remove)
int removed = minHeap.poll(); // 2 (removes)
Utility Methods (Collections class)
// Sorting
Collections.sort(list);
Collections.sort(list, Comparator.reverseOrder());
Collections.reverse(list);
Collections.shuffle(list);
// Searching (list must be sorted)
int index = Collections.binarySearch(list, "target");
// Min/Max
String min = Collections.min(list);
String max = Collections.max(list);
// Frequency and disjoint
int count = Collections.frequency(list, "item");
boolean noCommon = Collections.disjoint(list1, list2);
// Fill and copy
Collections.fill(list, "value"); // Replace all with value
Collections.copy(dest, src); // Copy src to dest
// Unmodifiable views
List<String> readOnly = Collections.unmodifiableList(list);
Set<String> readOnlySet = Collections.unmodifiableSet(set);
Map<K, V> readOnlyMap = Collections.unmodifiableMap(map);
// Synchronized wrappers
List<String> syncList = Collections.synchronizedList(list);
Map<K, V> syncMap = Collections.synchronizedMap(map);
// Empty collections
List<String> empty = Collections.emptyList();
Set<String> emptySet = Collections.emptySet();
Map<K, V> emptyMap = Collections.emptyMap();
// Singleton collections
List<String> single = Collections.singletonList("only");
Set<String> singleSet = Collections.singleton("only");
Creating Collections (Java 9+)
// Immutable collections
List<String> list = List.of("a", "b", "c");
Set<String> set = Set.of("a", "b", "c");
Map<String, Integer> map = Map.of("a", 1, "b", 2);
Map<String, Integer> map = Map.ofEntries(
Map.entry("a", 1),
Map.entry("b", 2)
);
// These throw UnsupportedOperationException on modification
Common Patterns
Count Occurrences
Map<String, Integer> counts = new HashMap<>();
for (String item : items) {
counts.merge(item, 1, Integer::sum);
}
// Or with streams
Map<String, Long> counts = items.stream()
.collect(Collectors.groupingBy(s -> s, Collectors.counting()));
Group by Property
Map<String, List<Person>> byCity = people.stream()
.collect(Collectors.groupingBy(Person::getCity));
Remove Duplicates from List
List<String> unique = new ArrayList<>(new HashSet<>(listWithDupes));
// Preserving order
List<String> unique = new ArrayList<>(new LinkedHashSet<>(listWithDupes));
// With streams
List<String> unique = list.stream().distinct().collect(Collectors.toList());
Convert Between Collections
// List to Set
Set<String> set = new HashSet<>(list);
// Set to List
List<String> list = new ArrayList<>(set);
// Array to List
List<String> list = Arrays.asList(array); // Fixed-size
List<String> list = new ArrayList<>(Arrays.asList(array)); // Modifiable
// List to Array
String[] array = list.toArray(new String[0]);
// Map keys/values to List
List<String> keys = new ArrayList<>(map.keySet());
List<Integer> values = new ArrayList<>(map.values());
Find Max/Min in Map by Value
Map.Entry<String, Integer> maxEntry = map.entrySet().stream()
.max(Map.Entry.comparingByValue())
.orElse(null);
String keyWithMaxValue = maxEntry.getKey();
Iterate Map and Modify
// Safe removal during iteration
map.entrySet().removeIf(entry -> entry.getValue() < 10);
// Using iterator
Iterator<Map.Entry<String, Integer>> it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, Integer> entry = it.next();
if (entry.getValue() < 10) {
it.remove();
}
}
Time Complexity Quick Reference
| Operation | ArrayList | LinkedList | HashSet | TreeSet | HashMap | TreeMap |
|---|---|---|---|---|---|---|
| add | O(1)* | O(1) | O(1) | O(log n) | O(1) | O(log n) |
| remove | O(n) | O(1)** | O(1) | O(log n) | O(1) | O(log n) |
| get/contains | O(1)/O(n) | O(n) | O(1) | O(log n) | O(1) | O(log n) |
| iteration | O(n) | O(n) | O(n) | O(n) | O(n) | O(n) |
* Amortized, occasional resize is O(n)
** O(1) if you have the node reference, O(n) to find by value
Related: Java Collections Framework Overview | ArrayList in Java | Introduction to Java Generics | Java Streams API
Sources
- Oracle. “Collections Framework Overview.” docs.oracle.com/javase/tutorial/collections
- Oracle. “java.util Package.” docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/package-summary.html


