Käytännön Esimerkkejä Stream API:n Käytöstä
Koodi ei ole pelkästään toiminnallisuutta—se on myös luettavuutta. Hyvin jäsennelty koodi on helpompi ylläpitää, muokata ja laajentaa.
Olet kehittäjä, jonka tehtävänä on arvioida jonkun toisen koodia ja tehdä siitä parempaa. Todellisissa projekteissa koodia kirjoitetaan usein kiireessä, kopioidaan eri ohjelman osista tai sitä ei yksinkertaisesti ole suunniteltu luettavuus edellä. Tehtäväsi ei ole vain ymmärtää koodia, vaan myös parantaa sitä—tehdä siitä selkeämpää, ytimekkäämpää ja helpommin ylläpidettävää.
Tällä hetkellä suoritat koodikatselmointia. Analysoit oikeaa koodiesimerkkiä, tunnistat sen heikkoudet ja refaktoroit sen vaihe vaiheelta käyttäen Stream APIa.
Aloitus
Kuvittele, että sinulla on verkkokauppa, ja sinun täytyy tunnistaa aktiiviset käyttäjät, jotka ovat tehneet vähintään kolme tilausta, joiden arvo on $10,000 tai enemmän. Tämä auttaa markkinointitiimiä tunnistamaan arvokkaimmat asiakkaat ja tarjoamaan heille henkilökohtaisia tarjouksia.
Tässä on alkuperäinen koodi ennen refaktorointia:
Main.java
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970package com.example; import java.util.ArrayList; import java.util.List; public class Main { public static void main(String[] args) { List<User> users = List.of( new User("Alice", true, List.of(new Order(12000), new Order(15000), new Order(11000))), new User("Bob", true, List.of(new Order(8000), new Order(9000), new Order(12000))), new User("Charlie", false, List.of(new Order(15000), new Order(16000), new Order(17000))), new User("David", true, List.of(new Order(5000), new Order(20000), new Order(30000))), new User("Eve", true, List.of(new Order(10000), new Order(10000), new Order(10000), new Order(12000))) ); List<User> premiumUsers = 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) { premiumUsers.add(user); } } } System.out.println("Premium users: " + premiumUsers); } } 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 + "'}"; } }
Sinulla on kaksi keskeistä luokkaa:
Order edustaa tilausta ja sisältää kentän total, joka tallentaa tilauksen summan.
User edustaa kaupan asiakasta ja siinä on kolme kenttää:
name(käyttäjän nimi);active(tilalippu);orders(tilausten lista).
Jokaisella User-oliolla on lista Order-olioita, mikä mallintaa todellisen tilanteen, jossa asiakas tekee useita tilauksia.
main-metodissa luodaan lista käyttäjistä, joilla jokaisella on oma tilausjoukkonsa. Ohjelma iteroi tämän listan läpi ja tarkistaa, onko käyttäjä aktiivinen. Jos ei ole, hänet ohitetaan.
Seuraavaksi ohjelma käy läpi käyttäjän tilaukset ja laskee, kuinka moni niistä on 10 000 dollarin arvoisia tai enemmän. Jos käyttäjällä on vähintään kolme tällaista tilausta, hänet lisätään premiumUsers-listaan.
Kun kaikki käyttäjät on käsitelty, ohjelma tulostaa premium-käyttäjät.
Koodin ongelmat
- Liikaa sisäkkäisiä silmukoita – vaikeuttaa lukemista ja ymmärtämistä;
- Turhaa koodia – liikaa manuaalisia tarkistuksia ja väliaikaisia muuttujia;
- Deklaratiivisen tyylin puute – koodi tuntuu matalan tason tietojenkäsittelyltä korkean tason logiikan sijaan.
Seuraavaksi uudistat tämän koodin vaiheittain käyttäen Stream APIa parantaaksesi luettavuutta, vähentääksesi toisteisuutta ja tehdäksesi siitä tehokkaamman.
Koodin uudelleenjärjestely
Ensimmäinen vaihe on poistaa ulompi if (user.isActive()) ja sisällyttää se suoraan Stream API:iin:
List<User> premiumUsers = users.stream()
.filter(User::isActive) // Keep only active users
.toList();
Nyt koodi on deklaratiivisempi ja osoittaa selkeästi, että suodatetaan aktiiviset käyttäjät. Tarpeeton if-ehto on poistettu—logiikka on nyt rakennettu suoraan Stream API:in. Tämä on kuitenkin vasta datan valmistelua, joten jatketaan eteenpäin!
Seuraavaksi korvataan sisäkkäinen for-silmukka (for (Order order : user.getOrders())) käyttämällä stream()-metodia filter-lauseessa:
List<User> premiumUsers = users.stream()
.filter(User::isActive)
.filter(user -> user.getOrders().stream()
.filter(order -> order.getTotal() >= 10000)
.count() >= 3) // Count orders directly in Stream API
.toList();
Manuaalisen laskennan poistaminen tekee koodista selkeämpää ja luettavampaa—nyt count() hoitaa tämän puolestamme, jolloin voimme käsitellä streamia ilman ylimääräisiä muuttujia.
Lopullinen uudistettu koodi
Nyt käytössä on täysin uudistettu ratkaisu, joka toteuttaa tehtävän deklaratiivisesti ja tiiviisti:
Main.java
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061package com.example; import java.util.List; public class Main { public static void main(String[] args) { List<User> users = List.of( new User("Alice", true, List.of(new Order(12000), new Order(15000), new Order(11000))), new User("Bob", true, List.of(new Order(8000), new Order(9000), new Order(12000))), new User("Charlie", false, List.of(new Order(15000), new Order(16000), new Order(17000))), new User("David", true, List.of(new Order(5000), new Order(20000), new Order(30000))), new User("Eve", true, List.of(new Order(10000), new Order(10000), new Order(10000), new Order(12000))) ); List<User> premiumUsers = users.stream() .filter(User::isActive) .filter(user -> user.getOrders().stream() .filter(order -> order.getTotal() >= 10000) .count() >= 3) .toList(); System.out.println("Premium users: " + premiumUsers); } } 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 + "'}"; } }
Koodi on nyt lyhyempi ja selkeämpi, koska sarjan manuaalisten tarkistusten sijaan käytetään deklaratiivista lähestymistapaa—keskittyen siihen, mitä pitää tehdä, eikä yksityiskohtaisesti jokaiseen prosessin vaiheeseen. Tämä poistaa tarpeen sisäkkäisille silmukoille, tehden koodista helpommin luettavaa ja ylläpidettävää.
Hyödyntämällä Stream API:a yhdistetään saumattomasti suodatus, laskenta ja datan kerääminen yhdeksi virraksi, mikä tekee koodista ilmaisullisempaa ja tehokkaampaa.
Kiitos palautteestasi!
Kysy tekoälyä
Kysy tekoälyä
Kysy mitä tahansa tai kokeile jotakin ehdotetuista kysymyksistä aloittaaksesi keskustelumme
Can you explain how the Stream API improves code readability in this example?
What are some potential drawbacks of using the Stream API in this scenario?
Can you show how the original (non-refactored) code looked for comparison?
Awesome!
Completion rate improved to 2.33
Käytännön Esimerkkejä Stream API:n Käytöstä
Pyyhkäise näyttääksesi valikon
Koodi ei ole pelkästään toiminnallisuutta—se on myös luettavuutta. Hyvin jäsennelty koodi on helpompi ylläpitää, muokata ja laajentaa.
Olet kehittäjä, jonka tehtävänä on arvioida jonkun toisen koodia ja tehdä siitä parempaa. Todellisissa projekteissa koodia kirjoitetaan usein kiireessä, kopioidaan eri ohjelman osista tai sitä ei yksinkertaisesti ole suunniteltu luettavuus edellä. Tehtäväsi ei ole vain ymmärtää koodia, vaan myös parantaa sitä—tehdä siitä selkeämpää, ytimekkäämpää ja helpommin ylläpidettävää.
Tällä hetkellä suoritat koodikatselmointia. Analysoit oikeaa koodiesimerkkiä, tunnistat sen heikkoudet ja refaktoroit sen vaihe vaiheelta käyttäen Stream APIa.
Aloitus
Kuvittele, että sinulla on verkkokauppa, ja sinun täytyy tunnistaa aktiiviset käyttäjät, jotka ovat tehneet vähintään kolme tilausta, joiden arvo on $10,000 tai enemmän. Tämä auttaa markkinointitiimiä tunnistamaan arvokkaimmat asiakkaat ja tarjoamaan heille henkilökohtaisia tarjouksia.
Tässä on alkuperäinen koodi ennen refaktorointia:
Main.java
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970package com.example; import java.util.ArrayList; import java.util.List; public class Main { public static void main(String[] args) { List<User> users = List.of( new User("Alice", true, List.of(new Order(12000), new Order(15000), new Order(11000))), new User("Bob", true, List.of(new Order(8000), new Order(9000), new Order(12000))), new User("Charlie", false, List.of(new Order(15000), new Order(16000), new Order(17000))), new User("David", true, List.of(new Order(5000), new Order(20000), new Order(30000))), new User("Eve", true, List.of(new Order(10000), new Order(10000), new Order(10000), new Order(12000))) ); List<User> premiumUsers = 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) { premiumUsers.add(user); } } } System.out.println("Premium users: " + premiumUsers); } } 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 + "'}"; } }
Sinulla on kaksi keskeistä luokkaa:
Order edustaa tilausta ja sisältää kentän total, joka tallentaa tilauksen summan.
User edustaa kaupan asiakasta ja siinä on kolme kenttää:
name(käyttäjän nimi);active(tilalippu);orders(tilausten lista).
Jokaisella User-oliolla on lista Order-olioita, mikä mallintaa todellisen tilanteen, jossa asiakas tekee useita tilauksia.
main-metodissa luodaan lista käyttäjistä, joilla jokaisella on oma tilausjoukkonsa. Ohjelma iteroi tämän listan läpi ja tarkistaa, onko käyttäjä aktiivinen. Jos ei ole, hänet ohitetaan.
Seuraavaksi ohjelma käy läpi käyttäjän tilaukset ja laskee, kuinka moni niistä on 10 000 dollarin arvoisia tai enemmän. Jos käyttäjällä on vähintään kolme tällaista tilausta, hänet lisätään premiumUsers-listaan.
Kun kaikki käyttäjät on käsitelty, ohjelma tulostaa premium-käyttäjät.
Koodin ongelmat
- Liikaa sisäkkäisiä silmukoita – vaikeuttaa lukemista ja ymmärtämistä;
- Turhaa koodia – liikaa manuaalisia tarkistuksia ja väliaikaisia muuttujia;
- Deklaratiivisen tyylin puute – koodi tuntuu matalan tason tietojenkäsittelyltä korkean tason logiikan sijaan.
Seuraavaksi uudistat tämän koodin vaiheittain käyttäen Stream APIa parantaaksesi luettavuutta, vähentääksesi toisteisuutta ja tehdäksesi siitä tehokkaamman.
Koodin uudelleenjärjestely
Ensimmäinen vaihe on poistaa ulompi if (user.isActive()) ja sisällyttää se suoraan Stream API:iin:
List<User> premiumUsers = users.stream()
.filter(User::isActive) // Keep only active users
.toList();
Nyt koodi on deklaratiivisempi ja osoittaa selkeästi, että suodatetaan aktiiviset käyttäjät. Tarpeeton if-ehto on poistettu—logiikka on nyt rakennettu suoraan Stream API:in. Tämä on kuitenkin vasta datan valmistelua, joten jatketaan eteenpäin!
Seuraavaksi korvataan sisäkkäinen for-silmukka (for (Order order : user.getOrders())) käyttämällä stream()-metodia filter-lauseessa:
List<User> premiumUsers = users.stream()
.filter(User::isActive)
.filter(user -> user.getOrders().stream()
.filter(order -> order.getTotal() >= 10000)
.count() >= 3) // Count orders directly in Stream API
.toList();
Manuaalisen laskennan poistaminen tekee koodista selkeämpää ja luettavampaa—nyt count() hoitaa tämän puolestamme, jolloin voimme käsitellä streamia ilman ylimääräisiä muuttujia.
Lopullinen uudistettu koodi
Nyt käytössä on täysin uudistettu ratkaisu, joka toteuttaa tehtävän deklaratiivisesti ja tiiviisti:
Main.java
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061package com.example; import java.util.List; public class Main { public static void main(String[] args) { List<User> users = List.of( new User("Alice", true, List.of(new Order(12000), new Order(15000), new Order(11000))), new User("Bob", true, List.of(new Order(8000), new Order(9000), new Order(12000))), new User("Charlie", false, List.of(new Order(15000), new Order(16000), new Order(17000))), new User("David", true, List.of(new Order(5000), new Order(20000), new Order(30000))), new User("Eve", true, List.of(new Order(10000), new Order(10000), new Order(10000), new Order(12000))) ); List<User> premiumUsers = users.stream() .filter(User::isActive) .filter(user -> user.getOrders().stream() .filter(order -> order.getTotal() >= 10000) .count() >= 3) .toList(); System.out.println("Premium users: " + premiumUsers); } } 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 + "'}"; } }
Koodi on nyt lyhyempi ja selkeämpi, koska sarjan manuaalisten tarkistusten sijaan käytetään deklaratiivista lähestymistapaa—keskittyen siihen, mitä pitää tehdä, eikä yksityiskohtaisesti jokaiseen prosessin vaiheeseen. Tämä poistaa tarpeen sisäkkäisille silmukoille, tehden koodista helpommin luettavaa ja ylläpidettävää.
Hyödyntämällä Stream API:a yhdistetään saumattomasti suodatus, laskenta ja datan kerääminen yhdeksi virraksi, mikä tekee koodista ilmaisullisempaa ja tehokkaampaa.
Kiitos palautteestasi!