Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Aprenda Desempenho na Stream API | Aplicações Práticas da Stream API
Stream API

bookDesempenho na Stream API

Você refatorou o código com sucesso, tornando-o mais limpo, mais curto e mais expressivo. Mas e quanto ao desempenho? Quão eficiente é a Stream API em comparação com os laços tradicionais? É possível acelerar utilizando parallelStream()? Vamos descobrir!

Medindo o Tempo de Execução

Para comparar desempenho de forma objetiva, será criado um conjunto de testes com 100.000 usuários e diferentes pedidos. Em seguida, serão implementadas três abordagens de filtragem:

  • for-loop tradicional – abordagem clássica com laços aninhados;
  • Stream API (stream()) – método declarativo moderno;
  • Parallel Stream API (parallelStream()) – processamento multithread.

O tempo de execução será medido utilizando System.nanoTime(), que fornece diferenças de tempo de alta precisão.

Implementação do Teste

Serão gerados 100.000 usuários, garantindo que todos possuam pedidos acima de $10,000, e todas as três abordagens serão executadas para verificar qual apresenta o melhor desempenho.

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 + "'}"; } }

Após executar o teste com 100.000 usuários, é possível observar as seguintes tendências:

O for-loop tradicional é mais rápido para operações simples, pois evita a sobrecarga da criação de streams e objetos adicionais. Apresenta melhor desempenho quando a velocidade bruta é prioridade.

A Stream API às vezes é um pouco mais lenta devido à criação de objetos adicionais, mas melhora significativamente a legibilidade e a manutenibilidade do código.

A Parallel Stream API pode acelerar o processamento em sistemas multi-core, mas nem sempre. Se o conjunto de dados for pequeno, a sobrecarga de gerenciamento de threads pode realmente diminuir a velocidade. Apresenta melhor desempenho em cálculos pesados, mas não ao modificar variáveis compartilhadas, pois as threads são executadas de forma independente.

Resumo

A Stream API é uma ferramenta poderosa que torna o código mais legível e conciso. No entanto, quando se trata de desempenho, é importante compreender suas limitações. Em alguns casos, laços for tradicionais são mais rápidos, especialmente ao trabalhar com conjuntos de dados pequenos. O parallelStream() pode melhorar a velocidade de processamento, mas requer testes para garantir que realmente oferece um benefício.

Portanto, a escolha da abordagem correta deve ser intencional: se a legibilidade for prioridade, utilize a Stream API; se o desempenho for crítico, teste e meça!

1. Qual abordagem é normalmente a mais rápida para operações simples?

2. Por que a Stream API pode ser mais lenta do que um laço regular?

3. Quando o parallelStream() pode diminuir a velocidade da execução?

question mark

Qual abordagem é normalmente a mais rápida para operações simples?

Select the correct answer

question mark

Por que a Stream API pode ser mais lenta do que um laço regular?

Select the correct answer

question mark

Quando o parallelStream() pode diminuir a velocidade da execução?

Select the correct answer

Tudo estava claro?

Como podemos melhorá-lo?

Obrigado pelo seu feedback!

Seção 4. Capítulo 2

Pergunte à IA

expand

Pergunte à IA

ChatGPT

Pergunte o que quiser ou experimente uma das perguntas sugeridas para iniciar nosso bate-papo

Awesome!

Completion rate improved to 2.33

bookDesempenho na Stream API

Deslize para mostrar o menu

Você refatorou o código com sucesso, tornando-o mais limpo, mais curto e mais expressivo. Mas e quanto ao desempenho? Quão eficiente é a Stream API em comparação com os laços tradicionais? É possível acelerar utilizando parallelStream()? Vamos descobrir!

Medindo o Tempo de Execução

Para comparar desempenho de forma objetiva, será criado um conjunto de testes com 100.000 usuários e diferentes pedidos. Em seguida, serão implementadas três abordagens de filtragem:

  • for-loop tradicional – abordagem clássica com laços aninhados;
  • Stream API (stream()) – método declarativo moderno;
  • Parallel Stream API (parallelStream()) – processamento multithread.

O tempo de execução será medido utilizando System.nanoTime(), que fornece diferenças de tempo de alta precisão.

Implementação do Teste

Serão gerados 100.000 usuários, garantindo que todos possuam pedidos acima de $10,000, e todas as três abordagens serão executadas para verificar qual apresenta o melhor desempenho.

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 + "'}"; } }

Após executar o teste com 100.000 usuários, é possível observar as seguintes tendências:

O for-loop tradicional é mais rápido para operações simples, pois evita a sobrecarga da criação de streams e objetos adicionais. Apresenta melhor desempenho quando a velocidade bruta é prioridade.

A Stream API às vezes é um pouco mais lenta devido à criação de objetos adicionais, mas melhora significativamente a legibilidade e a manutenibilidade do código.

A Parallel Stream API pode acelerar o processamento em sistemas multi-core, mas nem sempre. Se o conjunto de dados for pequeno, a sobrecarga de gerenciamento de threads pode realmente diminuir a velocidade. Apresenta melhor desempenho em cálculos pesados, mas não ao modificar variáveis compartilhadas, pois as threads são executadas de forma independente.

Resumo

A Stream API é uma ferramenta poderosa que torna o código mais legível e conciso. No entanto, quando se trata de desempenho, é importante compreender suas limitações. Em alguns casos, laços for tradicionais são mais rápidos, especialmente ao trabalhar com conjuntos de dados pequenos. O parallelStream() pode melhorar a velocidade de processamento, mas requer testes para garantir que realmente oferece um benefício.

Portanto, a escolha da abordagem correta deve ser intencional: se a legibilidade for prioridade, utilize a Stream API; se o desempenho for crítico, teste e meça!

1. Qual abordagem é normalmente a mais rápida para operações simples?

2. Por que a Stream API pode ser mais lenta do que um laço regular?

3. Quando o parallelStream() pode diminuir a velocidade da execução?

question mark

Qual abordagem é normalmente a mais rápida para operações simples?

Select the correct answer

question mark

Por que a Stream API pode ser mais lenta do que um laço regular?

Select the correct answer

question mark

Quando o parallelStream() pode diminuir a velocidade da execução?

Select the correct answer

Tudo estava claro?

Como podemos melhorá-lo?

Obrigado pelo seu feedback!

Seção 4. Capítulo 2
some-alt