Reaalimaailman 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 koodia, tunnistat sen heikkoudet ja refaktoroit sitä 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 sillä 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 monta tilausta on 10 000 dollarin tai enemmän arvoisia. 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 muistuttaa matalan tason tietojenkäsittelyä korkean tason logiikan sijaan.
Seuraavaksi uudistat tämän koodin vaihe vaiheelta 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:n rakenteeseen:
List<User> premiumUsers = users.stream()
.filter(User::isActive) // Keep only active users
.toList();
Nyt koodi on deklaratiivisempaa ja osoittaa selkeästi, että suodatetaan aktiivisia käyttäjiä. Tarpeeton if-ehto on poistettu—logiikka on nyt rakennettu suoraan Stream API:n sisään. 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()-kutsua filterin sisällä:
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äsi on täysin uudistettu ratkaisu, joka ratkaisee 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 käytät deklaratiivista lähestymistapaa peräkkäisten manuaalisten tarkistusten sijaan—keskittyen siihen, mitä pitää tehdä sen sijaan, että yksityiskohtaisesti määrittelisit jokaisen vaiheen. Tämä poistaa tarpeen sisäkkäisille silmukoille, tehden koodista helpommin luettavaa ja ylläpidettävää.
Hyödyntämällä Stream API:a yhdistät saumattomasti suodatuksen, laskennan ja datan keruun yhteen streamiin, mikä tekee koodista ilmeikkäämpää ja tehokkaampaa.
Kiitos palautteestasi!
Kysy tekoälyä
Kysy tekoälyä
Kysy mitä tahansa tai kokeile jotakin ehdotetuista kysymyksistä aloittaaksesi keskustelumme