Раздел 8 · 29 вопросов

Stream API

29 вопросов и ответов в разделе Stream API.

Russian Stream API Исходный Markdown
Версии по языкам: English Russian Ukrainian

Вопросы этого раздела

  1. Какие преимущества даёт использование Stream API?
  2. В чём разница между intermediate и terminal операциями?
  3. Что делает операция filter()?
  4. Что делает операция map()?
  5. Что делает операция collect()?
  6. Что такое Collector и какие есть встроенные Collectors?
  7. Что делает операция flatMap()?
  8. В чём разница между map() и flatMap()?
  9. Что такое параллельные стримы?
  10. Когда использовать parallel streams?
  11. Как создать parallel stream?
  12. Какие потенциальные проблемы могут быть с параллельными стримами?
  13. Что такое ForkJoinPool и как он связан с parallel streams?
  14. Можно ли изменять состояние внешних переменных в Stream операциях?
  15. Что такое побочные эффекты (side effects) в Stream?
  16. Почему следует избегать побочных эффектов в Stream?
  17. Что делает операция reduce()?
  18. В чём разница между reduce() и collect()?
  19. Что такое операция peek() и когда её использовать?
  20. Можно ли повторно использовать Stream?
  21. Что такое lazy evaluation в Stream?
  22. Когда начинается выполнение операций в Stream?
  23. Что делают операции distinct(), sorted(), limit(), skip()?
  24. Как работает короткое замыкание (short-circuiting) в Stream?
  25. Что такое операции anyMatch(), allMatch(), noneMatch()?
  26. Что делают операции findFirst() и findAny()?
  27. Как собрать Stream в Map?
  28. Что делать при коллизиях ключей при сборке в Map?
  29. Как работать с Optional в Stream?

Навигатор по разделу

29 вопросов для подготовки к собеседованию на Middle Java Developer.


📋 Все вопросы

# Вопрос Уровень сложности
1 Какие преимущества даёт использование Stream API
2 В чём разница между intermediate и terminal операциями
3 Что делает операция filter()
4 Что делает операция map()
5 Что делает операция collect() ⭐⭐
6 Что такое Collector и какие есть встроенные Collectors ⭐⭐
7 Что делает операция flatMap() ⭐⭐
8 В чём разница между map() и flatMap() ⭐⭐
9 Что такое параллельные стримы ⭐⭐⭐
10 Когда использовать parallel streams ⭐⭐⭐
11 Как создать параллельный стрим ⭐⭐
12 Какие потенциальные проблемы могут быть с параллельными стримами ⭐⭐⭐
13 Что такое ForkJoinPool и как он связан с parallel streams ⭐⭐⭐
14 Можно ли изменять состояние внешних переменных в Stream операциях ⭐⭐
15 Что такое побочные эффекты (side effects) в Stream ⭐⭐
16 Почему следует избегать побочных эффектов в Stream ⭐⭐
17 Что делает операция reduce() ⭐⭐
18 В чём разница между reduce() и collect() ⭐⭐
19 Что такое операция peek() и когда её использовать ⭐⭐
20 Можно ли повторно использовать Stream
21 Что такое lazy evaluation в Stream ⭐⭐
22 Когда начинается выполнение операций в Stream ⭐⭐
23 Что делают операции distinct(), sorted(), limit(), skip() ⭐⭐
24 Как работает короткое замыкание (short-circuiting) в Stream ⭐⭐
25 Что такое операции anyMatch(), allMatch(), noneMatch() ⭐⭐
26 Что делают операции findFirst() и findAny() ⭐⭐
27 Как собрать Stream в Map ⭐⭐
28 Что делать при коллизиях ключей при сборке в Map ⭐⭐⭐
29 Как работать с Optional в Stream ⭐⭐

🗺️ Карта зависимостей тем

                    ┌──────────────────────────────────────────┐
                    │   STREAM BASICS (1-2)                    │
                    │   1. Преимущества Stream API             │
                    │   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. Как создать    │
    │ 8. map vs fmap │        │ 8. map vs fmap│        │ 12. Проблемы       │
    │                │        │ 17. reduce()  │        │ 13. ForkJoinPool   │
    │                │        │ 18. reduce vs │        │                    │
    │                │        │     collect   │        │                    │
    └───────┬───────┘        └───────┬───────┘        └────────┬───────────┘
            │                        │                        │
            └────────────────────────┼────────────────────────┘
                                     ▼
                    ┌──────────────────────────────────────────┐
                    │   CONCEPTS & PITFALLS (14-22)            │
                    │   14. Внешние переменные                 │
                    │   15-16. Побочные эффекты                │
                    │   19. peek()                             │
                    │   20. Повторное использование            │
                    │   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 │        │                │        │                    │
    └───────────────┘        └───────────────┘        └────────────────────┘

🎯 Рекомендуемый порядок изучения

🟢 Уровень Junior (недели 1-2)

Шаг Тема Файлы Цель
1 Stream基本概念 Q1, Q2 Что такое Stream, lazy, intermediate vs terminal
2 Основные операции Q3, Q4 filter(), map()
3 collect() Q5 toList(), toSet(), joining()
4 map vs flatMap Q7, Q8 Когда map, когда flatMap
5 peek, reuse Q19, Q20 peek для отладки, нельзя переиспользовать
6 Lazy evaluation Q21, Q22 Когда начинается выполнение

🟡 Уровень Middle (недели 3-4)

Шаг Тема Файлы Цель
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 Когда parallel, когда sequential
4 Problems with parallel Q12, Q13 Cache locality, ForkJoinPool, work-stealing
5 Side effects Q14, Q15, Q16 Почему избегать, stateful ops
6 Advanced ops Q23, Q24, Q25 stateful ops, short-circuit, match
7 findFirst/findAny Q26 Ordered vs unordered, parallel impact

🔴 Уровень Senior (недели 5-6)

Шаг Тема Файлы Цель
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×Q > 10,000 rule, unordered optimization, custom FJP

🔗 Ключевые связи между темами

Тема: Основные операции

Q1 (Stream API) → Q2 (Intermediate vs Terminal) → Q3 (filter) → Q4 (map)
     ↓                                              ↓
Q7 (flatMap) ←────────────────────────────── Q8 (map vs flatMap)

Ключевые связи:

  • Q2 ↔ Q21: Intermediate операции ленивы, выполняются только при terminal
  • Q3 ↔ Q24: filter — short-circuit операция, может остановить пайплайн рано
  • Q4 ↔ Q7: map = 1→1, flatMap = 1→N + flatten
  • Q8 ↔ Q17: map преобразует, reduce/aggregates — сворачивает

Тема: Collect и Reduce

Q5 (collect) → Q6 (Collector) → Q17 (reduce) → Q18 (reduce vs collect)
     ↓              ↓
Q27 (toMap) → Q28 (Коллизии ключей)

Ключевые связи:

  • Q5 ↔ Q6: collect принимает Collector — «рецепт» сбора
  • Q6 ↔ Q18: Collector = mutable reduction, reduce = immutable reduction
  • Q17 ↔ Q18: reduce для простых значений, collect для коллекций
  • Q27 ↔ Q28: toMap бросает при дубликатах → merge function

Тема: Параллелизм

Q9 (Parallel streams) → Q10 (Когда использовать) → Q11 (Как создать)
     ↓                        ↓
Q12 (Проблемы) ←──── Q13 (ForkJoinPool)

Ключевые связи:

  • Q9 ↔ Q13: parallelStream = ForkJoinPool.commonPool()
  • Q10 ↔ Q12: Когда parallel помогает vs когда вредит
  • Q12 ↔ Q14: Side effects в parallel → race conditions
  • Q13 ↔ Q24: work-stealing алгоритм, LIFO/FIFO deque

Тема: Продвинутые операции

Q23 (distinct/sorted/limit/skip) → Q24 (Short-circuit)
     ↓                                    ↓
Q25 (anyMatch/allMatch/noneMatch) → Q26 (findFirst/findAny)
     ↓
Q29 (Optional)

Ключевые связи:

  • Q23 ↔ Q24: limit/skip/findFirst — short-circuit операции
  • Q24 ↔ Q25: match-операции = short-circuit terminal
  • Q25 ↔ Q26: anyMatch ≈ findAny().isPresent(), но без Optional overhead
  • Q26 ↔ Q29: findFirst/findAny возвращают Optional

🎓 Шпаргалка: что знать для каждого уровня

🟢 Junior

  • Stream ≠ Collection: Stream не хранит данные, это конвейер операций
  • Intermediate (filter, map, flatMap) — ленивые, terminal (collect, forEach, count) — запускают
  • filter = отсев, map = преобразование 1→1, flatMap = 1→N + flatten
  • collect = собрать результат в List/Map/Set
  • Stream нельзя переиспользовать — после terminal операции он исчерпан

🟡 Middle

  • Lazy evaluation: операции выполняются element-by-element, не stage-by-stage
  • Stateful операции (distinct, sorted) требуют знания всех элементов — убивают параллелизм
  • Short-circuit (findFirst, anyMatch, limit) — могут остановить пайплайн рано
  • parallelStream = ForkJoinPool.commonPool(), cores-1 воркеров
  • Side effects в Stream → баги в parallelStream, используйте collect вместо
  • reduce (immutable) vs collect (mutable) — collect эффективнее для коллекций

🔴 Senior

  • ForkJoinPool: per-thread Deque, LIFO для владельца, FIFO для воров
  • Spliterator характеристики: SIZED критичен для parallel (точный split)
  • N × Q > 10,000 правило: когда parallel окупается
  • Java 9+: count() оптимизирован для SIZED источников — peek не выполнится
  • orElse (eager) vs orElseGet (lazy) — orElseGet для дорогих дефолтов
  • Cache thrashing в parallel: потоки пишут в одну cache line → degradation
  • Custom ForkJoinPool для isolation, но не для I/O (используйте Virtual Threads)

📝 Формат каждого файла

Каждый файл содержит:

  • 🟢 Junior Level — базовое понимание, простые аналогии, примеры
  • 🟡 Middle Level — внутренности, типичные ошибки, практические примеры
  • 🔴 Senior Level — deep dive, edge cases, production experience, monitoring
  • 🎯 Шпаргалка для интервью — ключевые тезисы, частые вопросы, красные флаги, связанные темы