Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Вивчайте Продуктивність у Stream API | Практичне Застосування Stream API
Stream API

bookПродуктивність у Stream API

Ви успішно рефакторили код, зробивши його чистішим, коротшим та більш виразним. Але як щодо продуктивності? Наскільки ефективний Stream API у порівнянні з традиційними циклами? Чи можна прискорити його за допомогою parallelStream()? Давайте з’ясуємо!

Вимірювання часу виконання

Щоб об'єктивно порівняти продуктивність, буде створено тестовий набір даних із 100 000 користувачів та різними замовленнями. Далі буде реалізовано три підходи до фільтрації:

  • Традиційний for-loop – класичний підхід із вкладеними циклами;
  • Stream API (stream()) – сучасний декларативний метод;
  • Parallel Stream API (parallelStream()) – багатопотокова обробка.

Час виконання буде вимірюватися за допомогою System.nanoTime(), який забезпечує високоточні різниці часу.

Реалізація тесту

Буде згенеровано 100 000 користувачів, кожен із замовленнями понад $10 000, і виконано всі три підходи, щоб визначити, який із них показує найкращу продуктивність.

Main.java

Main.java

copy
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
package com.example; import java.util.ArrayList; import java.util.List; public class Main { public static void main(String[] args) { List<User> users = generateUsers(100000); // Measuring traditional loop execution time long startTime = System.nanoTime(); List<User> premiumUsersLoop = new ArrayList<>(); for (User user : users) { if (user.isActive()) { int totalOrders = 0; for (Order order : user.getOrders()) { if (order.getTotal() >= 10000) { totalOrders++; } } if (totalOrders >= 3) { premiumUsersLoop.add(user); } } } long endTime = System.nanoTime(); System.out.println("For-loop: " + (endTime - startTime) / 1_000_000 + " ms"); // Measuring Stream API execution time startTime = System.nanoTime(); List<User> premiumUsersStream = users.stream() .filter(User::isActive) .filter(user -> user.getOrders().stream() .filter(order -> order.getTotal() >= 10000) .count() >= 3) .toList(); endTime = System.nanoTime(); System.out.println("Stream API: " + (endTime - startTime) / 1_000_000 + " ms"); // Measuring Parallel Stream API execution time startTime = System.nanoTime(); List<User> premiumUsersParallelStream = users.parallelStream() .filter(User::isActive) .filter(user -> user.getOrders().stream() .filter(order -> order.getTotal() >= 10000) .count() >= 3) .toList(); endTime = System.nanoTime(); System.out.println("Parallel Stream API: " + (endTime - startTime) / 1_000_000 + " ms"); } private static List<User> generateUsers(int count) { List<User> users = new ArrayList<>(); for (int i = 0; i < count; i++) { users.add(new User("User" + i, true, List.of( new Order(14000), new Order(5000), new Order(7000) ))); } return users; } } class Order { private final double total; public Order(double total) { this.total = total; } public double getTotal() { return total; } } class User { private final String name; private final boolean active; private final List<Order> orders; public User(String name, boolean active, List<Order> orders) { this.name = name; this.active = active; this.orders = orders; } public boolean isActive() { return active; } public List<Order> getOrders() { return orders; } @Override public String toString() { return "User{name='" + name + "'}"; } }

Після запуску тесту з 100 000 користувачів можна спостерігати такі тенденції:

Традиційний for-loop є швидшим для простих операцій, оскільки уникає накладних витрат на створення потоку та додаткових об'єктів. Найкраще підходить, коли пріоритетом є максимальна швидкість.

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

Parallel Stream API може прискорити обробку на багатоядерних системах, але не завжди. Якщо набір даних невеликий, накладні витрати на керування потоками можуть навіть уповільнити виконання. Найкраще підходить для ресурсоємних обчислень, але не для зміни спільних змінних, оскільки потоки виконуються незалежно.

Підсумок

Stream API — це потужний інструмент, який робить код більш читабельним та лаконічним. Однак щодо продуктивності важливо розуміти його обмеження. У деяких випадках традиційні for-цикли працюють швидше, особливо при роботі з малими наборами даних. parallelStream() може підвищити швидкість обробки, але потребує тестування, щоб переконатися у реальній користі.

Отже, вибір підходу має бути усвідомленим: якщо важлива читабельність, використовуйте Stream API; якщо критична продуктивністьтестуйте та вимірюйте!

1. Який підхід зазвичай є найшвидшим для простих операцій?

2. Чому Stream API може бути повільнішим за звичайний цикл?

3. Коли використання parallelStream() може уповільнити виконання?

question mark

Який підхід зазвичай є найшвидшим для простих операцій?

Select the correct answer

question mark

Чому Stream API може бути повільнішим за звичайний цикл?

Select the correct answer

question mark

Коли використання parallelStream() може уповільнити виконання?

Select the correct answer

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

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

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

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

Запитати АІ

expand

Запитати АІ

ChatGPT

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

Awesome!

Completion rate improved to 2.33

bookПродуктивність у Stream API

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

Ви успішно рефакторили код, зробивши його чистішим, коротшим та більш виразним. Але як щодо продуктивності? Наскільки ефективний Stream API у порівнянні з традиційними циклами? Чи можна прискорити його за допомогою parallelStream()? Давайте з’ясуємо!

Вимірювання часу виконання

Щоб об'єктивно порівняти продуктивність, буде створено тестовий набір даних із 100 000 користувачів та різними замовленнями. Далі буде реалізовано три підходи до фільтрації:

  • Традиційний for-loop – класичний підхід із вкладеними циклами;
  • Stream API (stream()) – сучасний декларативний метод;
  • Parallel Stream API (parallelStream()) – багатопотокова обробка.

Час виконання буде вимірюватися за допомогою System.nanoTime(), який забезпечує високоточні різниці часу.

Реалізація тесту

Буде згенеровано 100 000 користувачів, кожен із замовленнями понад $10 000, і виконано всі три підходи, щоб визначити, який із них показує найкращу продуктивність.

Main.java

Main.java

copy
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
package com.example; import java.util.ArrayList; import java.util.List; public class Main { public static void main(String[] args) { List<User> users = generateUsers(100000); // Measuring traditional loop execution time long startTime = System.nanoTime(); List<User> premiumUsersLoop = new ArrayList<>(); for (User user : users) { if (user.isActive()) { int totalOrders = 0; for (Order order : user.getOrders()) { if (order.getTotal() >= 10000) { totalOrders++; } } if (totalOrders >= 3) { premiumUsersLoop.add(user); } } } long endTime = System.nanoTime(); System.out.println("For-loop: " + (endTime - startTime) / 1_000_000 + " ms"); // Measuring Stream API execution time startTime = System.nanoTime(); List<User> premiumUsersStream = users.stream() .filter(User::isActive) .filter(user -> user.getOrders().stream() .filter(order -> order.getTotal() >= 10000) .count() >= 3) .toList(); endTime = System.nanoTime(); System.out.println("Stream API: " + (endTime - startTime) / 1_000_000 + " ms"); // Measuring Parallel Stream API execution time startTime = System.nanoTime(); List<User> premiumUsersParallelStream = users.parallelStream() .filter(User::isActive) .filter(user -> user.getOrders().stream() .filter(order -> order.getTotal() >= 10000) .count() >= 3) .toList(); endTime = System.nanoTime(); System.out.println("Parallel Stream API: " + (endTime - startTime) / 1_000_000 + " ms"); } private static List<User> generateUsers(int count) { List<User> users = new ArrayList<>(); for (int i = 0; i < count; i++) { users.add(new User("User" + i, true, List.of( new Order(14000), new Order(5000), new Order(7000) ))); } return users; } } class Order { private final double total; public Order(double total) { this.total = total; } public double getTotal() { return total; } } class User { private final String name; private final boolean active; private final List<Order> orders; public User(String name, boolean active, List<Order> orders) { this.name = name; this.active = active; this.orders = orders; } public boolean isActive() { return active; } public List<Order> getOrders() { return orders; } @Override public String toString() { return "User{name='" + name + "'}"; } }

Після запуску тесту з 100 000 користувачів можна спостерігати такі тенденції:

Традиційний for-loop є швидшим для простих операцій, оскільки уникає накладних витрат на створення потоку та додаткових об'єктів. Найкраще підходить, коли пріоритетом є максимальна швидкість.

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

Parallel Stream API може прискорити обробку на багатоядерних системах, але не завжди. Якщо набір даних невеликий, накладні витрати на керування потоками можуть навіть уповільнити виконання. Найкраще підходить для ресурсоємних обчислень, але не для зміни спільних змінних, оскільки потоки виконуються незалежно.

Підсумок

Stream API — це потужний інструмент, який робить код більш читабельним та лаконічним. Однак щодо продуктивності важливо розуміти його обмеження. У деяких випадках традиційні for-цикли працюють швидше, особливо при роботі з малими наборами даних. parallelStream() може підвищити швидкість обробки, але потребує тестування, щоб переконатися у реальній користі.

Отже, вибір підходу має бути усвідомленим: якщо важлива читабельність, використовуйте Stream API; якщо критична продуктивністьтестуйте та вимірюйте!

1. Який підхід зазвичай є найшвидшим для простих операцій?

2. Чому Stream API може бути повільнішим за звичайний цикл?

3. Коли використання parallelStream() може уповільнити виконання?

question mark

Який підхід зазвичай є найшвидшим для простих операцій?

Select the correct answer

question mark

Чому Stream API може бути повільнішим за звичайний цикл?

Select the correct answer

question mark

Коли використання parallelStream() може уповільнити виконання?

Select the correct answer

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

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

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

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