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)