Suorituskyky Stream API:ssa
Pyyhkäise näyttääksesi valikon
Olet onnistuneesti refaktoroinut koodin, tehden siitä selkeämmän, lyhyemmän ja ilmaisullisemman.
Mutta entä suorituskyky? Kuinka tehokas Stream API on verrattuna perinteisiin silmukoihin? Voiko parallelStream() nopeuttaa sitä? Otetaan selvää!
Suorituksen ajan mittaaminen
Objektiivisen suorituskyvyn vertailun vuoksi luodaan testiaineisto, jossa on 100 000 käyttäjää ja erilaisia tilauksia. Toteutetaan kolme suodatustapaa:
- Perinteinen
for-loop– klassinen ratkaisu sisäkkäisillä silmukoilla; - Stream API (
stream()) – moderni deklaratiivinen menetelmä; - Parallel Stream API (
parallelStream()) – monisäikeinen käsittely.
Suoritusaika mitataan käyttäen System.nanoTime(), joka tarjoaa tarkan aikamittauksen.
Testin toteutus
Luodaan 100 000 käyttäjää, joilla kaikilla on yli 10 000 dollarin tilaukset, ja ajetaan kaikki kolme menetelmää nähdäksemme, mikä niistä on tehokkain.
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 + "'}"; } }
Suoritettaessa testiä 100 000 käyttäjällä voidaan havaita seuraavia suuntauksia:
Perinteinen for-loop on nopeampi yksinkertaisissa operaatioissa, koska se välttää streamin luonnista ja ylimääräisistä olioista aiheutuvan ylikuorman. Se suoriutuu parhaiten, kun raaka nopeus on ensisijainen tavoite.
Stream API on joskus hieman hitaampi ylimääräisten stream-olioiden vuoksi, mutta se parantaa merkittävästi koodin luettavuutta ja ylläpidettävyyttä.
Rinnakkaisella Stream API:lla voidaan nopeuttaa käsittelyä moniydinkoneilla, mutta ei aina. Jos aineisto on pieni, säikeiden hallinnasta aiheutuva ylikuorma voi itse asiassa hidastaa toimintaa. Se soveltuu parhaiten raskaisiin laskentatehtäviin, mutta ei silloin, kun jaettuja muuttujia muokataan, koska säikeet toimivat itsenäisesti.
Yhteenveto
Stream API on tehokas työkalu, joka tekee koodista luettavampaa ja ytimekkäämpää. Kuitenkin suorituskyvyn osalta on tärkeää ymmärtää sen rajoitukset. Joissakin tapauksissa perinteiset for-silmukat ovat nopeampia, erityisesti pienten tietoaineistojen kanssa työskenneltäessä. parallelStream() voi parantaa käsittelynopeutta, mutta sen hyöty tulee varmistaa testaamalla.
Oikean lähestymistavan valinta tulee tehdä tarkoituksellisesti: jos luettavuus on etusijalla, käytä Stream APIa; jos suorituskyky on kriittistä, testaa ja mittaa!
1. Mikä lähestymistapa on tyypillisesti nopein yksinkertaisissa operaatioissa?
2. Miksi Stream API voi olla hitaampi kuin tavallinen silmukka?
3. Milloin parallelStream() voi hidastaa suoritusta?
Kiitos palautteestasi!
Kysy tekoälyä
Kysy tekoälyä
Kysy mitä tahansa tai kokeile jotakin ehdotetuista kysymyksistä aloittaaksesi keskustelumme