Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Вивчайте Обробка Елементів за Допомогою Методу forEach() | Термінальні Операції у Stream API
Stream API

bookОбробка Елементів за Допомогою Методу forEach()

Ви вже знайомі з методом forEach(), оскільки використовували його на практиці для виведення кожного елемента колекції у консоль. Розгляньмо його детальніше та дослідимо його реалізації.

Він забезпечує зручний спосіб обробки даних у функціональному стилі. Однак важливо зазначити, що порядок обробки залежить від типу потоку та використаного методу.

У Stream API існує дві реалізації методу forEach(). Розглянемо їх по черзі.

Метод forEach

Виконує дію над кожним елементом, але порядок обробки не гарантується у паралельних потоках.

void forEach(Consumer<? super T> action)

Метод forEach() приймає як аргумент Consumer<T>функціональний інтерфейс, який визначає операцію для кожного елемента у потоці. Зазвичай використовується для логування, виведення інформації або виконання побічних ефектів.

Практичний приклад

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

Main.java

Main.java

copy
1234567891011121314151617181920212223
package com.example; import java.util.List; import java.util.stream.Stream; public class Main { public static void main(String[] args) { List<String> customers = List.of( "alice@example.com", "bob@example.com", "charlie@example.com" ); // Parallel stream for faster processing Stream<String> customerStream = customers.parallelStream(); customerStream.forEach(email -> sendDiscountEmail(email)); } private static void sendDiscountEmail(String email) { System.out.println("Sending discount email to: " + email); // Simulating email sending process } }

Цей код імітує надсилання персоналізованих листів зі знижками для клієнтів. Оскільки використовується parallelStream(), листи надсилаються у довільному порядку для підвищення швидкості. Метод forEach() застосовує вказану дію до кожної електронної адреси.

Метод forEachOrdered

Виконує дію з збереженням порядку елементів, навіть у паралельних потоках.

void forEachOrdered(Consumer<? super T> action)

Як і forEach, цей метод також приймає Consumer<T>, але гарантує, що елементи обробляються у тому ж порядку, в якому вони з'являються в оригінальному потоці. Це корисно, коли важливо зберігати послідовність.

Практичний приклад

Уявіть собі платіжну систему, де кожна транзакція повинна оброблятися в точному порядку надходження. Якщо платежі обробляються не по порядку, це може призвести до помилок, наприклад, неправильного розрахунку балансу.

Main.java

Main.java

copy
123456789101112131415161718192021
package com.example; import java.util.List; import java.util.stream.Stream; public class Main { public static void main(String[] args) { List<String> payments = List.of( "Payment #5001 - $100", "Payment #5002 - $250", "Payment #5003 - $75" ); Stream<String> paymentStream = payments.parallelStream(); paymentStream.forEachOrdered(payment -> processPayment(payment)); } private static void processPayment(String payment) { System.out.println("Processing payment: " + payment); } }

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

Порівняння продуктивності: forEach() проти forEachOrdered()

Оцінимо, наскільки швидше виконується forEach() порівняно з forEachOrdered() при роботі з паралельними потоками. Для цього створіть список із 10 мільйонів елементів, обробіть їх обома методами, обчислюючи квадратний корінь кожного числа, та зафіксуйте час виконання.

Main.java

Main.java

copy
12345678910111213141516171819202122232425262728293031
package com.example; import java.util.List; import java.util.stream.IntStream; import java.util.ArrayList; public class Main { public static void main(String[] args) { List<Integer> numbers = new ArrayList<>(); IntStream.range(0, 10_000_000).forEach(numbers::add); // Create a list with 10 million elements // Measure execution time of `forEach()` long startTime = System.nanoTime(); numbers.parallelStream().forEach(num -> process(num)); long forEachTime = System.nanoTime() - startTime; // Measure execution time of `forEachOrdered()` startTime = System.nanoTime(); numbers.parallelStream().forEachOrdered(num -> process(num)); long forEachOrderedTime = System.nanoTime() - startTime; // Print results System.out.println("forEach execution time: " + forEachTime / 1_000_000 + " ms"); System.out.println("forEachOrdered execution time: " + forEachOrderedTime / 1_000_000 + " ms"); } private static void process(int num) { // Simulate workload Math.sqrt(num); } }

forEach() обробляє елементи без збереження порядку, дозволяючи потоку вільно розподіляти завдання між доступними ядрами процесора. Це максимізує продуктивність, оскільки кожен потік може брати елементи у будь-якому порядку та обробляти їх паралельно без обмежень.

Метод forEachOrdered() зберігає оригінальний порядок елементів, що вимагає додаткової синхронізації. У паралельному потоці елементи спочатку розбиваються на частини для обробки, але їхні результати потім мають бути зібрані у правильному порядку перед передачею у метод обробки.

1. Який функціональний інтерфейс приймає метод forEach?

2. Який результат може вивести цей код?

question mark

Який функціональний інтерфейс приймає метод forEach?

Select the correct answer

question mark

Який результат може вивести цей код?

Select the correct answer

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

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

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

Секція 3. Розділ 4

Запитати АІ

expand

Запитати АІ

ChatGPT

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

Awesome!

Completion rate improved to 2.33

bookОбробка Елементів за Допомогою Методу forEach()

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

Ви вже знайомі з методом forEach(), оскільки використовували його на практиці для виведення кожного елемента колекції у консоль. Розгляньмо його детальніше та дослідимо його реалізації.

Він забезпечує зручний спосіб обробки даних у функціональному стилі. Однак важливо зазначити, що порядок обробки залежить від типу потоку та використаного методу.

У Stream API існує дві реалізації методу forEach(). Розглянемо їх по черзі.

Метод forEach

Виконує дію над кожним елементом, але порядок обробки не гарантується у паралельних потоках.

void forEach(Consumer<? super T> action)

Метод forEach() приймає як аргумент Consumer<T>функціональний інтерфейс, який визначає операцію для кожного елемента у потоці. Зазвичай використовується для логування, виведення інформації або виконання побічних ефектів.

Практичний приклад

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

Main.java

Main.java

copy
1234567891011121314151617181920212223
package com.example; import java.util.List; import java.util.stream.Stream; public class Main { public static void main(String[] args) { List<String> customers = List.of( "alice@example.com", "bob@example.com", "charlie@example.com" ); // Parallel stream for faster processing Stream<String> customerStream = customers.parallelStream(); customerStream.forEach(email -> sendDiscountEmail(email)); } private static void sendDiscountEmail(String email) { System.out.println("Sending discount email to: " + email); // Simulating email sending process } }

Цей код імітує надсилання персоналізованих листів зі знижками для клієнтів. Оскільки використовується parallelStream(), листи надсилаються у довільному порядку для підвищення швидкості. Метод forEach() застосовує вказану дію до кожної електронної адреси.

Метод forEachOrdered

Виконує дію з збереженням порядку елементів, навіть у паралельних потоках.

void forEachOrdered(Consumer<? super T> action)

Як і forEach, цей метод також приймає Consumer<T>, але гарантує, що елементи обробляються у тому ж порядку, в якому вони з'являються в оригінальному потоці. Це корисно, коли важливо зберігати послідовність.

Практичний приклад

Уявіть собі платіжну систему, де кожна транзакція повинна оброблятися в точному порядку надходження. Якщо платежі обробляються не по порядку, це може призвести до помилок, наприклад, неправильного розрахунку балансу.

Main.java

Main.java

copy
123456789101112131415161718192021
package com.example; import java.util.List; import java.util.stream.Stream; public class Main { public static void main(String[] args) { List<String> payments = List.of( "Payment #5001 - $100", "Payment #5002 - $250", "Payment #5003 - $75" ); Stream<String> paymentStream = payments.parallelStream(); paymentStream.forEachOrdered(payment -> processPayment(payment)); } private static void processPayment(String payment) { System.out.println("Processing payment: " + payment); } }

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

Порівняння продуктивності: forEach() проти forEachOrdered()

Оцінимо, наскільки швидше виконується forEach() порівняно з forEachOrdered() при роботі з паралельними потоками. Для цього створіть список із 10 мільйонів елементів, обробіть їх обома методами, обчислюючи квадратний корінь кожного числа, та зафіксуйте час виконання.

Main.java

Main.java

copy
12345678910111213141516171819202122232425262728293031
package com.example; import java.util.List; import java.util.stream.IntStream; import java.util.ArrayList; public class Main { public static void main(String[] args) { List<Integer> numbers = new ArrayList<>(); IntStream.range(0, 10_000_000).forEach(numbers::add); // Create a list with 10 million elements // Measure execution time of `forEach()` long startTime = System.nanoTime(); numbers.parallelStream().forEach(num -> process(num)); long forEachTime = System.nanoTime() - startTime; // Measure execution time of `forEachOrdered()` startTime = System.nanoTime(); numbers.parallelStream().forEachOrdered(num -> process(num)); long forEachOrderedTime = System.nanoTime() - startTime; // Print results System.out.println("forEach execution time: " + forEachTime / 1_000_000 + " ms"); System.out.println("forEachOrdered execution time: " + forEachOrderedTime / 1_000_000 + " ms"); } private static void process(int num) { // Simulate workload Math.sqrt(num); } }

forEach() обробляє елементи без збереження порядку, дозволяючи потоку вільно розподіляти завдання між доступними ядрами процесора. Це максимізує продуктивність, оскільки кожен потік може брати елементи у будь-якому порядку та обробляти їх паралельно без обмежень.

Метод forEachOrdered() зберігає оригінальний порядок елементів, що вимагає додаткової синхронізації. У паралельному потоці елементи спочатку розбиваються на частини для обробки, але їхні результати потім мають бути зібрані у правильному порядку перед передачею у метод обробки.

1. Який функціональний інтерфейс приймає метод forEach?

2. Який результат може вивести цей код?

question mark

Який функціональний інтерфейс приймає метод forEach?

Select the correct answer

question mark

Який результат може вивести цей код?

Select the correct answer

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

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

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

Секція 3. Розділ 4
some-alt