Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Вивчайте Принципи | Основи Та Функціональні Можливості Stream API
Stream API

bookПринципи

Принципи роботи з Stream API ґрунтуються на ключових концепціях функціонального програмування та лінивої оцінки. Розглянемо основні принципи Stream API.

Лінива оцінка

Одним із основних принципів Stream API є лінива оцінка.

Це означає, що проміжні операції, такі як filter() або map(), не виконуються одразу. Вони лише формують ланцюжок дій, який буде виконано лише під час виклику термінальної операції, наприклад, collect() або forEach().

Main.java

Main.java

copy
12345678910111213
package com.example; import java.util.List; public class Main { public static void main(String[] args) { List<String> names = List.of("Alice", "Bob", "Charlie"); long count = names.stream() .filter(name -> name.startsWith("A")) // Forming the operation .count(); // Triggering execution System.out.println(count); // Output: 1 } }

Цей код створює потік із списку рядків, фільтрує елементи, залишаючи лише ті, що починаються з літери A, і підраховує, скільки з них відповідають умові. Результат (1) виводиться, оскільки лише Alice задовольняє умову.

Функціональний стиль програмування

Stream API використовує лямбда-вирази та функціональні інтерфейси для обробки даних. Замість імперативного підходу з циклами описується, що саме потрібно зробити з даними:

Main.java

Main.java

copy
1234567891011121314
package com.example; import java.util.List; public class Main { public static void main(String[] args) { List<String> fruits = List.of("apple", "banana", "cherry", "apricot", "blueberry"); List<String> result = fruits.stream() .map(String::toUpperCase) // Convert all strings to uppercase .skip(3) .toList(); // Collect the result into a new list System.out.println(result); } }

Цей код створює потік з списку фруктів, перетворює рядки у верхній регістр за допомогою map(), і пропускає перші три елементи за допомогою skip(). Результат збирається у новий список і виводиться, починаючи з четвертого елемента.

Незмінність даних

Stream API не змінює оригінальні дані. Усі операції створюють новий потік або повертають результат без зміни колекції чи масиву. Це підвищує безпеку даних і запобігає неочікуваним побічним ефектам.

Main.java

Main.java

copy
12345678910111213
package com.example; import java.util.List; public class Main { public static void main(String[] args) { List<String> names = List.of("Alice", "Bob", "Charlie"); List<String> updateNames = names.stream() .filter(name -> name.startsWith("A")) .toList(); System.out.println(names); // Output: [Alice, Bob, Charlie] } }

Stream API фільтрує list names для створення нового потоку updateNames, який містить лише елементи, що починаються з літери A. Однак оригінальний list names залишається незмінним, оскільки Stream API не змінює дані безпосередньо, забезпечуючи безпеку даних та запобігаючи побічним ефектам.

Потоки використовуються лише один раз

Потік можна використати лише один раз. Після виконання термінальної операції потік стає недоступним для подальшої обробки.

Main.java

Main.java

copy
123456789101112
package com.example; import java.util.List; import java.util.stream.Stream; public class Main { public static void main(String[] args) { Stream<String> stream = List.of("Alice", "Bob").stream(); stream.forEach(System.out::println); stream.forEach(System.out::println); // Error: Stream has already been used } }

Тут створюється потік з списку рядків і виводиться кожен елемент у консоль. Після першого використання потік не можна використати повторно, що призводить до помилки при спробі знову викликати forEach().

Паралельна обробка

Stream API підтримує паралельні потоки, що забезпечує швидшу обробку даних на багатоядерних системах. Це розглядається детальніше тут

Main.java

Main.java

copy
1234567891011
package com.example; import java.util.List; public class Main { public static void main(String[] args) { List<Integer> numbers = List.of(1, 2, 3, 4, 5); numbers.parallelStream() .forEach(System.out::println); // Elements are processed in parallel } }

Цей код створює паралельний потік з списку чисел та виводить кожен елемент у консоль. Використання parallelStream() дозволяє здійснювати паралельну обробку елементів списку, що може прискорити виконання при роботі з великими наборами даних.

Чистота та читабельність коду

Використання Stream API робить код більш декларативним. Замість опису як виконати завдання (наприклад, використовуючи цикли), ви описуєте що саме потрібно зробити. Це підвищує читабельність та спрощує супровід коду.

Приклад з циклом:

List<String> names = List.of("Alice", "Bob", "Charlie");
for (String name : names) {
    System.out.println(name);
}

Приклад використання Stream API:

List<String> names = List.of("Alice", "Bob", "Charlie");
names.stream().forEach(System.out::println);

У першому прикладі з циклом явно описується, як ітеруватися по списку та виводити елементи, тоді як у другому прикладі з Stream API просто вказується, що потрібно зробити: пройтися по елементах і вивести їх. Це робить код більш декларативним і читабельним.

Все було зрозуміло?

Як ми можемо покращити це?

Дякуємо за ваш відгук!

Секція 1. Розділ 2

Запитати АІ

expand

Запитати АІ

ChatGPT

Запитайте про що завгодно або спробуйте одне із запропонованих запитань, щоб почати наш чат

Suggested prompts:

Can you explain more about lazy evaluation in the Stream API?

What are some common terminal and intermediate operations in streams?

How does the Stream API improve code readability compared to traditional loops?

Awesome!

Completion rate improved to 2.33

bookПринципи

Свайпніть щоб показати меню

Принципи роботи з Stream API ґрунтуються на ключових концепціях функціонального програмування та лінивої оцінки. Розглянемо основні принципи Stream API.

Лінива оцінка

Одним із основних принципів Stream API є лінива оцінка.

Це означає, що проміжні операції, такі як filter() або map(), не виконуються одразу. Вони лише формують ланцюжок дій, який буде виконано лише під час виклику термінальної операції, наприклад, collect() або forEach().

Main.java

Main.java

copy
12345678910111213
package com.example; import java.util.List; public class Main { public static void main(String[] args) { List<String> names = List.of("Alice", "Bob", "Charlie"); long count = names.stream() .filter(name -> name.startsWith("A")) // Forming the operation .count(); // Triggering execution System.out.println(count); // Output: 1 } }

Цей код створює потік із списку рядків, фільтрує елементи, залишаючи лише ті, що починаються з літери A, і підраховує, скільки з них відповідають умові. Результат (1) виводиться, оскільки лише Alice задовольняє умову.

Функціональний стиль програмування

Stream API використовує лямбда-вирази та функціональні інтерфейси для обробки даних. Замість імперативного підходу з циклами описується, що саме потрібно зробити з даними:

Main.java

Main.java

copy
1234567891011121314
package com.example; import java.util.List; public class Main { public static void main(String[] args) { List<String> fruits = List.of("apple", "banana", "cherry", "apricot", "blueberry"); List<String> result = fruits.stream() .map(String::toUpperCase) // Convert all strings to uppercase .skip(3) .toList(); // Collect the result into a new list System.out.println(result); } }

Цей код створює потік з списку фруктів, перетворює рядки у верхній регістр за допомогою map(), і пропускає перші три елементи за допомогою skip(). Результат збирається у новий список і виводиться, починаючи з четвертого елемента.

Незмінність даних

Stream API не змінює оригінальні дані. Усі операції створюють новий потік або повертають результат без зміни колекції чи масиву. Це підвищує безпеку даних і запобігає неочікуваним побічним ефектам.

Main.java

Main.java

copy
12345678910111213
package com.example; import java.util.List; public class Main { public static void main(String[] args) { List<String> names = List.of("Alice", "Bob", "Charlie"); List<String> updateNames = names.stream() .filter(name -> name.startsWith("A")) .toList(); System.out.println(names); // Output: [Alice, Bob, Charlie] } }

Stream API фільтрує list names для створення нового потоку updateNames, який містить лише елементи, що починаються з літери A. Однак оригінальний list names залишається незмінним, оскільки Stream API не змінює дані безпосередньо, забезпечуючи безпеку даних та запобігаючи побічним ефектам.

Потоки використовуються лише один раз

Потік можна використати лише один раз. Після виконання термінальної операції потік стає недоступним для подальшої обробки.

Main.java

Main.java

copy
123456789101112
package com.example; import java.util.List; import java.util.stream.Stream; public class Main { public static void main(String[] args) { Stream<String> stream = List.of("Alice", "Bob").stream(); stream.forEach(System.out::println); stream.forEach(System.out::println); // Error: Stream has already been used } }

Тут створюється потік з списку рядків і виводиться кожен елемент у консоль. Після першого використання потік не можна використати повторно, що призводить до помилки при спробі знову викликати forEach().

Паралельна обробка

Stream API підтримує паралельні потоки, що забезпечує швидшу обробку даних на багатоядерних системах. Це розглядається детальніше тут

Main.java

Main.java

copy
1234567891011
package com.example; import java.util.List; public class Main { public static void main(String[] args) { List<Integer> numbers = List.of(1, 2, 3, 4, 5); numbers.parallelStream() .forEach(System.out::println); // Elements are processed in parallel } }

Цей код створює паралельний потік з списку чисел та виводить кожен елемент у консоль. Використання parallelStream() дозволяє здійснювати паралельну обробку елементів списку, що може прискорити виконання при роботі з великими наборами даних.

Чистота та читабельність коду

Використання Stream API робить код більш декларативним. Замість опису як виконати завдання (наприклад, використовуючи цикли), ви описуєте що саме потрібно зробити. Це підвищує читабельність та спрощує супровід коду.

Приклад з циклом:

List<String> names = List.of("Alice", "Bob", "Charlie");
for (String name : names) {
    System.out.println(name);
}

Приклад використання Stream API:

List<String> names = List.of("Alice", "Bob", "Charlie");
names.stream().forEach(System.out::println);

У першому прикладі з циклом явно описується, як ітеруватися по списку та виводити елементи, тоді як у другому прикладі з Stream API просто вказується, що потрібно зробити: пройтися по елементах і вивести їх. Це робить код більш декларативним і читабельним.

Все було зрозуміло?

Як ми можемо покращити це?

Дякуємо за ваш відгук!

Секція 1. Розділ 2
some-alt