Prestaties in Stream API
Je hebt de code succesvol gerefactord, waardoor deze netter, korter en meer expressief is geworden.
Maar hoe zit het met de prestaties? Hoe efficiënt is de Stream API vergeleken met traditionele lussen? Kun je het versnellen met parallelStream()? Laten we het ontdekken!
Uitvoertijd meten
Om de prestaties objectief te vergelijken, maken we een testdataset met 100.000 gebruikers en verschillende bestellingen. Vervolgens implementeren we drie filtermethoden:
- Traditionele
for-loop– een klassieke aanpak met geneste lussen; - Stream API (
stream()) – een moderne declaratieve methode; - Parallel Stream API (
parallelStream()) – multithreaded verwerking.
Je meet de uitvoertijd met System.nanoTime(), dat nauwkeurige tijdsverschillen biedt.
Testimplementatie
Je genereert 100.000 gebruikers, waarbij je ervoor zorgt dat ze allemaal bestellingen boven de $10.000 hebben, en voert alle drie de methoden uit om te zien welke het beste presteert.
Main.java
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100package 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 + "'}"; } }
Na het uitvoeren van de test met 100.000 gebruikers, kunnen de volgende trends worden waargenomen:
De traditionele for-loop is sneller bij eenvoudige bewerkingen omdat deze geen overhead heeft van stream-creatie en extra objecten. Dit levert de beste prestaties wanneer ruwe snelheid prioriteit heeft.
De Stream API is soms iets trager door extra stream-objecten, maar verbetert aanzienlijk de leesbaarheid en onderhoudbaarheid van de code.
De Parallel Stream API kan de verwerking versnellen op multi-core systemen, maar niet altijd. Als de dataset klein is, kan de overhead van threadbeheer het juist vertragen. Dit werkt het beste bij zware berekeningen, maar niet bij het wijzigen van gedeelde variabelen, omdat threads onafhankelijk van elkaar draaien.
Samenvatting
Stream API is een krachtig hulpmiddel dat code leesbaarder en bondiger maakt. Echter, als het gaat om prestaties, is het belangrijk om de beperkingen te begrijpen. In sommige gevallen zijn traditionele for-loops sneller, vooral bij het werken met kleine datasets. parallelStream() kan de verwerkingssnelheid verhogen, maar vereist testen om te verzekeren dat het daadwerkelijk een voordeel oplevert.
Het kiezen van de juiste aanpak moet dus bewust gebeuren: als leesbaarheid prioriteit heeft, gebruik dan de Stream API; als prestaties cruciaal zijn, test en meet!
1. Welke aanpak is doorgaans het snelst voor eenvoudige bewerkingen?
2. Waarom kan Stream API langzamer zijn dan een gewone lus?
3. Wanneer kan parallelStream() de uitvoering vertragen?
Bedankt voor je feedback!
Vraag AI
Vraag AI
Vraag wat u wilt of probeer een van de voorgestelde vragen om onze chat te starten.
Awesome!
Completion rate improved to 2.33
Prestaties in Stream API
Veeg om het menu te tonen
Je hebt de code succesvol gerefactord, waardoor deze netter, korter en meer expressief is geworden.
Maar hoe zit het met de prestaties? Hoe efficiënt is de Stream API vergeleken met traditionele lussen? Kun je het versnellen met parallelStream()? Laten we het ontdekken!
Uitvoertijd meten
Om de prestaties objectief te vergelijken, maken we een testdataset met 100.000 gebruikers en verschillende bestellingen. Vervolgens implementeren we drie filtermethoden:
- Traditionele
for-loop– een klassieke aanpak met geneste lussen; - Stream API (
stream()) – een moderne declaratieve methode; - Parallel Stream API (
parallelStream()) – multithreaded verwerking.
Je meet de uitvoertijd met System.nanoTime(), dat nauwkeurige tijdsverschillen biedt.
Testimplementatie
Je genereert 100.000 gebruikers, waarbij je ervoor zorgt dat ze allemaal bestellingen boven de $10.000 hebben, en voert alle drie de methoden uit om te zien welke het beste presteert.
Main.java
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100package 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 + "'}"; } }
Na het uitvoeren van de test met 100.000 gebruikers, kunnen de volgende trends worden waargenomen:
De traditionele for-loop is sneller bij eenvoudige bewerkingen omdat deze geen overhead heeft van stream-creatie en extra objecten. Dit levert de beste prestaties wanneer ruwe snelheid prioriteit heeft.
De Stream API is soms iets trager door extra stream-objecten, maar verbetert aanzienlijk de leesbaarheid en onderhoudbaarheid van de code.
De Parallel Stream API kan de verwerking versnellen op multi-core systemen, maar niet altijd. Als de dataset klein is, kan de overhead van threadbeheer het juist vertragen. Dit werkt het beste bij zware berekeningen, maar niet bij het wijzigen van gedeelde variabelen, omdat threads onafhankelijk van elkaar draaien.
Samenvatting
Stream API is een krachtig hulpmiddel dat code leesbaarder en bondiger maakt. Echter, als het gaat om prestaties, is het belangrijk om de beperkingen te begrijpen. In sommige gevallen zijn traditionele for-loops sneller, vooral bij het werken met kleine datasets. parallelStream() kan de verwerkingssnelheid verhogen, maar vereist testen om te verzekeren dat het daadwerkelijk een voordeel oplevert.
Het kiezen van de juiste aanpak moet dus bewust gebeuren: als leesbaarheid prioriteit heeft, gebruik dan de Stream API; als prestaties cruciaal zijn, test en meet!
1. Welke aanpak is doorgaans het snelst voor eenvoudige bewerkingen?
2. Waarom kan Stream API langzamer zijn dan een gewone lus?
3. Wanneer kan parallelStream() de uitvoering vertragen?
Bedankt voor je feedback!