Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Oppiskele Käytännön Esimerkkejä Stream API:n Käytöstä | Stream API:n Käytännön Sovellukset
Stream API

bookKä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

Main.java

copy
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
package 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

Main.java

copy
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
package 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.

Oliko kaikki selvää?

Miten voimme parantaa sitä?

Kiitos palautteestasi!

Osio 4. Luku 1

Kysy tekoälyä

expand

Kysy tekoälyä

ChatGPT

Kysy mitä tahansa tai kokeile jotakin ehdotetuista kysymyksistä aloittaaksesi keskustelumme

Suggested prompts:

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?

bookKä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

Main.java

copy
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
package 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

Main.java

copy
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
package 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.

Oliko kaikki selvää?

Miten voimme parantaa sitä?

Kiitos palautteestasi!

Osio 4. Luku 1
some-alt