Розділ 8 · 29 питань

Stream API

29 питань і відповідей у розділі Stream API.

Ukrainian 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 Як створити 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 ⭐⭐

🗺️ Карта залежностей тем

                    ┌──────────────────────────────────────────┐
                    │   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. Коли використо│
    │ 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. Колізії    │        │                    │
    │    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 → деградація
  • Custom ForkJoinPool для ізоляції, але не для I/O (використовуйте Virtual Threads)

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

Кожен файл містить:

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