Eksempler fra virkeligheten på bruk av Stream API
Kode handler ikke bare om funksjonalitet—det handler også om lesbarhet. Godt strukturert kode er enklere å vedlikeholde, endre og utvide.
Du er en utvikler som har fått i oppgave å gjennomgå andres kode og gjøre den bedre. I virkelige prosjekter blir kode ofte skrevet i hastverk, kopiert fra ulike deler av programmet, eller rett og slett ikke laget med lesbarhet i tankene. Din oppgave er ikke bare å forstå koden, men å forbedre den—gjøre den renere, mer konsis og enklere å vedlikeholde.
Akkurat nå utfører du en kodegjennomgang. Du skal analysere et ekte kodeeksempel, identifisere svake punkter, og refaktorere det steg for steg ved bruk av Stream API.
Komme i gang
Tenk deg at du har en nettbutikk, og du må identifisere aktive brukere som har lagt inn minst tre bestillinger på $10,000 eller mer. Dette vil hjelpe markedsføringsteamet med å gjenkjenne de mest verdifulle kundene og tilby dem personlige tilbud.
Her er startkoden før refaktorering:
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 + "'}"; } }
Du har to nøkkelklasser:
Order representerer en ordre og inneholder et total-felt som lagrer ordresummen.
User representerer en butikkunde med tre felt:
name(brukernavn);active(statusflagg);orders(liste over ordrer).
Hver User inneholder en liste med Order-objekter, som modellerer et virkelighetstro scenario der en kunde legger inn flere ordrer.
I main opprettes en liste med brukere, hver med sitt eget sett med ordrer. Programmet itererer deretter gjennom denne listen og sjekker om en bruker er aktiv. Hvis ikke, blir de hoppet over.
Deretter looper programmet gjennom brukerens ordrer og teller hvor mange som er på $10,000 eller mer. Hvis brukeren har minst tre kvalifiserende ordrer, legges de til i listen premiumUsers.
Når alle brukere er behandlet, skrives listen over premium-brukere ut.
Problemer med koden
- For mange nøstede løkker – gjør det vanskeligere å lese og forstå;
- Redundant kode – for mange manuelle sjekker og mellomliggende variabler;
- Mangler deklarativ stil – koden fremstår som lavnivå databehandling i stedet for høynivå logikk.
Du skal nå refaktorere denne koden steg for steg ved hjelp av Stream API for å forbedre lesbarheten, redusere overflødighet og gjøre den mer effektiv.
Kodeomstrukturering
Første steg er å fjerne den ytre if (user.isActive()) og integrere den direkte i Stream API:
List<User> premiumUsers = users.stream()
.filter(User::isActive) // Keep only active users
.toList();
Nå er koden mer deklarativ og viser tydelig at du filtrerer aktive brukere. Den unødvendige if-betingelsen er fjernet—logikken er nå bygget direkte inn i Stream API. Dette er imidlertid kun dataklargjøring, så la oss gå videre!
Neste steg er å erstatte den nøstede for-løkken (for (Order order : user.getOrders())) med en stream() inne i filter:
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();
Ved å eliminere manuell telling har du gjort koden renere og mer lesbar—nå håndterer count() dette for oss, slik at vi kan arbeide med streamen uten ekstra variabler.
Endelig refaktorert kode
Nå har du en fullstendig refaktorert løsning som løser oppgaven på en deklarativ og kortfattet måte:
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 + "'}"; } }
Koden er nå kortere og tydeligere fordi du, i stedet for en rekke manuelle kontroller, bruker en deklarativ tilnærming—fokuserer på hva som skal gjøres i stedet for å beskrive hvert enkelt steg i prosessen. Dette eliminerer behovet for nøstede løkker, noe som gjør koden enklere å lese og vedlikeholde.
Ved å utnytte Stream API kombinerer du sømløst filtrering, telling og datainnsamling i én enkelt stream, noe som gjør koden mer uttrykksfull og effektiv.
Takk for tilbakemeldingene dine!
Spør AI
Spør AI
Spør om hva du vil, eller prøv ett av de foreslåtte spørsmålene for å starte chatten vår
Awesome!
Completion rate improved to 2.33
Eksempler fra virkeligheten på bruk av Stream API
Sveip for å vise menyen
Kode handler ikke bare om funksjonalitet—det handler også om lesbarhet. Godt strukturert kode er enklere å vedlikeholde, endre og utvide.
Du er en utvikler som har fått i oppgave å gjennomgå andres kode og gjøre den bedre. I virkelige prosjekter blir kode ofte skrevet i hastverk, kopiert fra ulike deler av programmet, eller rett og slett ikke laget med lesbarhet i tankene. Din oppgave er ikke bare å forstå koden, men å forbedre den—gjøre den renere, mer konsis og enklere å vedlikeholde.
Akkurat nå utfører du en kodegjennomgang. Du skal analysere et ekte kodeeksempel, identifisere svake punkter, og refaktorere det steg for steg ved bruk av Stream API.
Komme i gang
Tenk deg at du har en nettbutikk, og du må identifisere aktive brukere som har lagt inn minst tre bestillinger på $10,000 eller mer. Dette vil hjelpe markedsføringsteamet med å gjenkjenne de mest verdifulle kundene og tilby dem personlige tilbud.
Her er startkoden før refaktorering:
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 + "'}"; } }
Du har to nøkkelklasser:
Order representerer en ordre og inneholder et total-felt som lagrer ordresummen.
User representerer en butikkunde med tre felt:
name(brukernavn);active(statusflagg);orders(liste over ordrer).
Hver User inneholder en liste med Order-objekter, som modellerer et virkelighetstro scenario der en kunde legger inn flere ordrer.
I main opprettes en liste med brukere, hver med sitt eget sett med ordrer. Programmet itererer deretter gjennom denne listen og sjekker om en bruker er aktiv. Hvis ikke, blir de hoppet over.
Deretter looper programmet gjennom brukerens ordrer og teller hvor mange som er på $10,000 eller mer. Hvis brukeren har minst tre kvalifiserende ordrer, legges de til i listen premiumUsers.
Når alle brukere er behandlet, skrives listen over premium-brukere ut.
Problemer med koden
- For mange nøstede løkker – gjør det vanskeligere å lese og forstå;
- Redundant kode – for mange manuelle sjekker og mellomliggende variabler;
- Mangler deklarativ stil – koden fremstår som lavnivå databehandling i stedet for høynivå logikk.
Du skal nå refaktorere denne koden steg for steg ved hjelp av Stream API for å forbedre lesbarheten, redusere overflødighet og gjøre den mer effektiv.
Kodeomstrukturering
Første steg er å fjerne den ytre if (user.isActive()) og integrere den direkte i Stream API:
List<User> premiumUsers = users.stream()
.filter(User::isActive) // Keep only active users
.toList();
Nå er koden mer deklarativ og viser tydelig at du filtrerer aktive brukere. Den unødvendige if-betingelsen er fjernet—logikken er nå bygget direkte inn i Stream API. Dette er imidlertid kun dataklargjøring, så la oss gå videre!
Neste steg er å erstatte den nøstede for-løkken (for (Order order : user.getOrders())) med en stream() inne i filter:
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();
Ved å eliminere manuell telling har du gjort koden renere og mer lesbar—nå håndterer count() dette for oss, slik at vi kan arbeide med streamen uten ekstra variabler.
Endelig refaktorert kode
Nå har du en fullstendig refaktorert løsning som løser oppgaven på en deklarativ og kortfattet måte:
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 + "'}"; } }
Koden er nå kortere og tydeligere fordi du, i stedet for en rekke manuelle kontroller, bruker en deklarativ tilnærming—fokuserer på hva som skal gjøres i stedet for å beskrive hvert enkelt steg i prosessen. Dette eliminerer behovet for nøstede løkker, noe som gjør koden enklere å lese og vedlikeholde.
Ved å utnytte Stream API kombinerer du sømløst filtrering, telling og datainnsamling i én enkelt stream, noe som gjør koden mer uttrykksfull og effektiv.
Takk for tilbakemeldingene dine!