Stream API
29 interview questions and answers in the Stream API section.
Questions in this section
- What advantages does Stream API provide?
- What is the difference between intermediate and terminal operations?
- What does filter() operation do?
- What does map() operation do?
- What does collect() operation do?
- What is Collector and what built-in Collectors exist?
- What does flatMap() operation do?
- What is the difference between map() and flatMap()?
- What are parallel streams?
- When to use parallel streams?
- How to create a parallel stream?
- What potential problems can occur with parallel streams?
- What is ForkJoinPool and how is it related to parallel streams?
- Can you modify state of external variables in Stream operations?
- What are side effects in Stream?
- Why you should avoid side effects in Stream?
- What does reduce() operation do?
- What is the difference between reduce() and collect()?
- What is peek() operation and when to use it?
- Can you reuse a Stream?
- What is lazy evaluation in Stream?
- When does Stream operation execution begin?
- What do distinct(), sorted(), limit(), skip() operations do?
- How does short-circuiting work in Stream?
- What are anyMatch(), allMatch(), noneMatch() operations?
- What do findFirst() and findAny() operations do?
- How to collect Stream into Map?
- What to do about key collisions when collecting into Map?
- How to work with Optional in Stream?
Study navigator
29 questions for preparing for a Middle Java Developer interview.
All Questions
Topic Dependency Map
┌──────────────────────────────────────────┐
│ STREAM BASICS (1-2) │
│ 1. Stream API Advantages │
│ 2. Intermediate vs Terminal │
└──────────────────┬───────────────────────┘
│
┌──────────────────────────┼──────────────────────────┐
▼ ▼ ▼
┌───────────────┐ ┌───────────────┐ ┌────────────────────┐
│ CORE OPS │ │ COLLECT & │ │ PARALLEL │
│ (3-8) │ │ REDUCE (5-8) │ │ (9-13) │
│ 3. filter() │ │ 5. collect() │ │ 9. Parallel streams│
│ 4. map() │ │ 6. Collector │ │ 10. When to use │
│ 7. flatMap() │ │ 7. flatMap() │ │ 11. How to create │
│ 8. map vs fmap │ │ 8. map vs fmap│ │ 12. Problems │
│ │ │ 17. reduce() │ │ 13. ForkJoinPool │
│ │ │ 18. reduce vs │ │ │
│ │ │ collect │ │ │
└───────┬───────┘ └───────┬───────┘ └────────┬───────────┘
│ │ │
└────────────────────────┼────────────────────────┘
▼
┌──────────────────────────────────────────┐
│ CONCEPTS & PITFALLS (14-22) │
│ 14. External variables │
│ 15-16. Side effects │
│ 19. peek() │
│ 20. Reuse │
│ 21-22. Lazy evaluation │
└──────────────────────────────────────────┘
│
┌────────────────────────┼────────────────────────┐
▼ ▼ ▼
┌───────────────┐ ┌───────────────┐ ┌────────────────────┐
│ ADVANCED OPS │ │ MAP & OPT │ │ │
│ (23-26) │ │ (27-29) │ │ │
│ 23. distinct, │ │ 27. toMap │ │ │
│ sorted, │ │ 28. Collisions │ │ │
│ limit, skip│ │ 29. Optional │ │ │
│ 24. Short-cir│ │ │ │ │
│ 25. match() │ │ │ │ │
│ 26. findFirst │ │ │ │ │
└───────────────┘ └───────────────┘ └────────────────────┘
Recommended Study Order
Junior Level (weeks 1-2)
| Step | Topic | Files | Goal |
|---|---|---|---|
| 1 | Stream Basics | Q1, Q2 | What is Stream, lazy, intermediate vs terminal |
| 2 | Core Operations | Q3, Q4 | filter(), map() |
| 3 | collect() | Q5 | toList(), toSet(), joining() |
| 4 | map vs flatMap | Q7, Q8 | When to use map, when flatMap |
| 5 | peek, reuse | Q19, Q20 | peek for debugging, cannot reuse |
| 6 | Lazy evaluation | Q21, Q22 | When execution begins |
Middle Level (weeks 3-4)
| Step | Topic | Files | Goal |
|---|---|---|---|
| 1 | Collector deep dive | Q6 | characteristics, custom Collector, teeing |
| 2 | reduce vs collect | Q17, Q18 | Immutable vs mutable reduction |
| 3 | Parallel streams | Q9, Q10, Q11 | When parallel, when sequential |
| 4 | Problems with parallel | Q12, Q13 | Cache locality, ForkJoinPool, work-stealing |
| 5 | Side effects | Q14, Q15, Q16 | Why to avoid, stateful ops |
| 6 | Advanced ops | Q23, Q24, Q25 | stateful ops, short-circuit, match |
| 7 | findFirst/findAny | Q26 | Ordered vs unordered, parallel impact |
Senior Level (weeks 5-6)
| Step | Topic | Files | Goal |
|---|---|---|---|
| 1 | ForkJoinPool internals | Q13 (Senior) | Deque, LIFO/FIFO, work-stealing algorithm |
| 2 | Collector internals | Q6 (Senior) | Supplier/Accumulator/Combiner/Finisher, characteristics |
| 3 | Parallel pitfalls | Q12 (Senior) | Cache thrashing, ThreadLocal, boxed primitives |
| 4 | Short-circuit optimization | Q24 (Senior) | Java 9+ count() optimization, SIZED sources |
| 5 | Map collection pitfalls | Q27, Q28 | toMap vs groupingBy, merge function, parallel combiner |
| 6 | Optional in Stream | Q29 | orElse vs orElseGet, flatMap with Optional |
| 7 | Performance tuning | Q9-Q13 (Senior) | N x Q > 10,000 rule, unordered optimization, custom FJP |
Key Connections Between Topics
Topic: Core Operations
Q1 (Stream API) → Q2 (Intermediate vs Terminal) → Q3 (filter) → Q4 (map)
↓ ↓
Q7 (flatMap) ←────────────────────────────── Q8 (map vs flatMap)
Key connections:
- Q2 <-> Q21: Intermediate operations are lazy, executed only on terminal
- Q3 <-> Q24: filter is a short-circuit operation, can stop pipeline early
- Q4 <-> Q7: map = 1->1, flatMap = 1->N + flatten
- Q8 <-> Q17: map transforms, reduce/aggregates — collapses
Topic: Collect and Reduce
Q5 (collect) → Q6 (Collector) → Q17 (reduce) → Q18 (reduce vs collect)
↓ ↓
Q27 (toMap) → Q28 (Key Collisions)
Key connections:
- Q5 <-> Q6: collect takes a Collector — a “recipe” for collecting
- Q6 <-> Q18: Collector = mutable reduction, reduce = immutable reduction
- Q17 <-> Q18: reduce for simple values, collect for collections
- Q27 <-> Q28: toMap throws on duplicates -> merge function
Topic: Concurrency
Q9 (Parallel streams) → Q10 (When to use) → Q11 (How to create)
↓ ↓
Q12 (Problems) ←──── Q13 (ForkJoinPool)
Key connections:
- Q9 <-> Q13: parallelStream = ForkJoinPool.commonPool()
- Q10 <-> Q12: When parallel helps vs when it hurts
- Q12 <-> Q14: Side effects in parallel -> race conditions
- Q13 <-> Q24: work-stealing algorithm, LIFO/FIFO deque
Topic: Advanced Operations
Q23 (distinct/sorted/limit/skip) → Q24 (Short-circuit)
↓ ↓
Q25 (anyMatch/allMatch/noneMatch) → Q26 (findFirst/findAny)
↓
Q29 (Optional)
Key connections:
- Q23 <-> Q24: limit/skip/findFirst are short-circuit operations
- Q24 <-> Q25: match operations = short-circuit terminal
- Q25 <-> Q26: anyMatch approx findAny().isPresent(), but without Optional overhead
- Q26 <-> Q29: findFirst/findAny return Optional
Cheat Sheet: What to Know for Each Level
Junior
- Stream != Collection: Stream does not store data, it is an operation pipeline
- Intermediate (filter, map, flatMap) — lazy, terminal (collect, forEach, count) — trigger execution
- filter = filtering, map = 1->1 transformation, flatMap = 1->N + flatten
- collect = collect result into List/Map/Set
- Stream cannot be reused — exhausted after terminal operation
Middle
- Lazy evaluation: operations execute element-by-element, not stage-by-stage
- Stateful operations (distinct, sorted) require knowledge of all elements — kill parallelism
- Short-circuit (findFirst, anyMatch, limit) — can stop pipeline early
- parallelStream = ForkJoinPool.commonPool(), cores-1 workers
- Side effects in Stream -> bugs in parallelStream, use collect instead
- reduce (immutable) vs collect (mutable) — collect is more efficient for collections
Senior
- ForkJoinPool: per-thread Deque, LIFO for owner, FIFO for thieves
- Spliterator characteristics: SIZED is critical for parallel (exact split)
- N x Q > 10,000 rule: when parallel pays off
- Java 9+: count() optimized for SIZED sources — peek won’t execute
- orElse (eager) vs orElseGet (lazy) — orElseGet for expensive defaults
- Cache thrashing in parallel: threads write to same cache line -> degradation
- Custom ForkJoinPool for isolation, but not for I/O (use Virtual Threads)
File Format
Each file contains:
- Junior Level — basic understanding, simple analogies, examples
- Middle Level — internals, typical mistakes, practical examples
- Senior Level — deep dive, edge cases, production experience, monitoring
- Interview Cheat Sheet — key points, common questions, red flags, related topics