Collections and Streams in Java
Who is this for?
Absolute beginners who want a single, deep-dive document covering every common data structure and stream operation used in real Java code and DSA problems. Every section includes what it is, when to use it, how to create it, all key methods with examples, and gotchas to avoid.
Video Explanation

1. Collections Framework Overview
The Java Collections Framework is a unified architecture for storing and manipulating groups of objects. Every structure in this document lives under java.util.
Iterable
└── Collection
├── List → ordered, index-based, duplicates allowed
│ ├── ArrayList
│ └── LinkedList
├── Set → no duplicates
│ ├── HashSet
│ ├── LinkedHashSet
│ └── TreeSet
└── Queue → FIFO ordering
├── LinkedList
├── ArrayDeque
└── PriorityQueue
Map (NOT a Collection, but part of the framework)
├── HashMap
├── LinkedHashMap
└── TreeMap
Key interfaces to know:
List<E>— ordered sequence, access by indexSet<E>— unique elements onlyQueue<E>— FIFO; poll from front, add to rearDeque<E>— double-ended queue; use as stack or queueMap<K,V>— key-value pairs, keys are unique
2. ArrayList
What is it?
A resizable array backed by a plain Object[] under the hood. When the array fills up, Java creates a new array 1.5× the old size and copies everything over.
When to use it?
- You need fast random access by index (
O(1)). - You mostly add/read elements, not insert in the middle.
- Most common List you'll use in DSA (adjacency lists, storing results, etc.).
How to create
import java.util.ArrayList;
import java.util.List;
// Empty list
ArrayList<Integer> list = new ArrayList<>();
// With initial capacity (avoids resizing early — good for performance)
ArrayList<Integer> list2 = new ArrayList<>(100);
// From an existing collection
ArrayList<Integer> list3 = new ArrayList<>(List.of(1, 2, 3, 4, 5));
// Using the interface type (best practice)
List<String> names = new ArrayList<>();
Key Methods
Adding Elements
List<String> fruits = new ArrayList<>();
fruits.add("Apple"); // adds to end → ["Apple"]
fruits.add("Banana"); // → ["Apple", "Banana"]
fruits.add(0, "Mango"); // insert at index 0 → ["Mango", "Apple", "Banana"]
fruits.addAll(List.of("Kiwi", "Grape")); // add entire collection at end
fruits.addAll(1, List.of("Peach")); // add collection at index 1
Accessing Elements
String first = fruits.get(0); // "Mango" — O(1)
int size = fruits.size(); // total number of elements
// Iterate with for-each
for (String f : fruits) {
System.out.println(f);
}
// Iterate with index
for (int i = 0; i < fruits.size(); i++) {
System.out.println(i + ": " + fruits.get(i));
}
// forEach with lambda
fruits.forEach(f -> System.out.println(f));
Searching
boolean has = fruits.contains("Apple"); // true — O(n)
int idx = fruits.indexOf("Apple"); // first occurrence index, or -1
int lastIdx = fruits.lastIndexOf("Apple"); // last occurrence index, or -1
Modifying
fruits.set(0, "Papaya"); // replace element at index 0 — O(1)
Removing Elements
fruits.remove(0); // remove by index — O(n) due to shifting
fruits.remove("Banana"); // remove by value (first occurrence) — O(n)
fruits.removeAll(List.of("Kiwi", "Grape")); // remove all matching
fruits.retainAll(List.of("Apple", "Mango")); // keep ONLY these
fruits.clear(); // remove everything
Sorting
List<Integer> nums = new ArrayList<>(List.of(5, 2, 8, 1));
Collections.sort(nums); // natural order → [1, 2, 5, 8]
Collections.sort(nums, Collections.reverseOrder()); // reverse → [8, 5, 2, 1]
nums.sort(Comparator.naturalOrder()); // same as Collections.sort
nums.sort(Comparator.reverseOrder());
nums.sort((a, b) -> a - b); // custom lambda comparator
Sublist & Conversion
List<Integer> sub = nums.subList(1, 3); // [index 1, index 3) — view, not copy!
// List → Array
Integer[] arr = nums.toArray(new Integer[0]);
// Array → List (fixed size!)
List<Integer> fromArr = Arrays.asList(1, 2, 3); // cannot add/remove
// Mutable version:
List<Integer> mutable = new ArrayList<>(Arrays.asList(1, 2, 3));
Complexity
| Operation | Time |
|---|---|
get(i) | O(1) |
add(e) at end | O(1) amortized |
add(i, e) in middle | O(n) |
remove(i) | O(n) |
contains(e) | O(n) |
Common Gotchas
// Removing by int vs Integer!
List<Integer> list = new ArrayList<>(List.of(1, 2, 3));
list.remove(1); // removes by INDEX → list is [1, 3]
list.remove((Integer) 1); // removes by VALUE → list is [2, 3]
// ConcurrentModificationException — never modify while iterating
for (Integer n : list) {
list.remove(n); // CRASH! Use Iterator or removeIf instead
}
list.removeIf(n -> n % 2 == 0); // safe removal
3. LinkedList
What is it?
A doubly-linked list where each node holds a value plus pointers to the previous and next node. It implements both List and Deque.