Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Lære Virkelige Eksempler på Brug af Stream API | Praktiske Anvendelser af Stream API
Stream API

bookVirkelige Eksempler på Brug af Stream API

Kode handler ikke kun om funktionalitet—det handler også om læsbarhed. Velstruktureret kode er lettere at vedligeholde, ændre og udvide.

Du er en udvikler, der har til opgave at gennemgå en andens kode og gøre den bedre. I virkelige projekter bliver kode ofte skrevet i hast, kopieret fra forskellige dele af programmet eller blot ikke designet med læsbarhed for øje. Din opgave er ikke kun at forstå koden, men også at forbedre den—gøre den renere, mere kortfattet og lettere at vedligeholde.

Lige nu udfører du et kodegennemgang. Du vil analysere et reelt stykke kode, identificere dets svage punkter og refaktorere det trin for trin ved hjælp af Stream API.

Kom godt i gang

Forestil dig, at du har en onlinebutik, og du skal identificere aktive brugere, der har afgivet mindst tre ordrer$10.000 eller mere. Dette vil hjælpe marketingteamet med at genkende de mest værdifulde kunder og tilbyde dem personlige tilbud.

Her er den oprindelige kode før refaktorering:

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 + "'}"; } }

Du har to nøgleklasser:

Order repræsenterer en ordre og indeholder et total-felt, der gemmer ordrens beløb. User repræsenterer en butikskunde med tre felter:

  • name (brugerens navn);
  • active (statusflag);
  • orders (liste over ordrer).

Hver User indeholder en liste af Order-objekter, hvilket modellerer et virkelighedsnært scenarie, hvor en kunde afgiver flere ordrer.

I main oprettes en liste af brugere, hver med deres eget sæt af ordrer. Programmet gennemløber derefter denne liste og kontrollerer, om en bruger er aktiv. Hvis ikke, springes de over.

Dernæst gennemløber programmet brugerens ordrer og tæller, hvor mange der er på $10.000 eller mere. Hvis brugeren har mindst tre kvalificerende ordrer, tilføjes de til listen premiumUsers.

Når alle brugere er behandlet, udskriver programmet de premium-brugere.

Problemer med koden

  • For mange indlejrede løkker – gør det sværere at læse og forstå;
  • Redundant kode – for mange manuelle tjek og mellemliggende variabler;
  • Mangel på deklarativ stil – koden føles som lavniveau databehandling i stedet for høj-niveau logik.

Du vil nu refaktorere denne kode trin for trin ved hjælp af Stream API for at forbedre læsbarheden, reducere redundans og gøre den mere effektiv.

Kodeomstrukturering

Første trin er at fjerne den ydre if (user.isActive()) og integrere den direkte i Stream API:

List<User> premiumUsers = users.stream()
        .filter(User::isActive)  // Keep only active users
        .toList();

Nu er koden mere deklarativ og viser tydeligt, at du filtrerer aktive brugere. Den unødvendige if-betingelse er fjernet—logikken er nu bygget direkte ind i Stream API. Dette er dog kun dataklargøring, så lad os gå videre!

Dernæst skal vi erstatte den indlejrede for-løkke (for (Order order : user.getOrders())) med et stream() inde 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 at eliminere manuel optælling er koden blevet renere og mere læsbar—nu håndterer count() dette for os, hvilket gør det muligt at arbejde med streamen uden ekstra variabler.

Endelig refaktoreret kode

Nu foreligger en fuldt refaktoreret løsning, der løser opgaven på en deklarativ og kortfattet måde:

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 + "'}"; } }

Koden er nu kortere og mere overskuelig, fordi du i stedet for en række manuelle kontroller anvender en deklarativ tilgang—med fokus på, hvad der skal gøres, frem for at beskrive hvert enkelt trin i processen. Dette eliminerer behovet for indlejrede løkker, hvilket gør koden lettere at læse og vedligeholde.

Ved at udnytte Stream API kombineres filtrering, optælling og datainnsamling problemfrit i én enkelt stream, hvilket gør koden mere udtryksfuld og effektiv.

Var alt klart?

Hvordan kan vi forbedre det?

Tak for dine kommentarer!

Sektion 4. Kapitel 1

Spørg AI

expand

Spørg AI

ChatGPT

Spørg om hvad som helst eller prøv et af de foreslåede spørgsmål for at starte vores chat

Awesome!

Completion rate improved to 2.33

bookVirkelige Eksempler på Brug af Stream API

Stryg for at vise menuen

Kode handler ikke kun om funktionalitet—det handler også om læsbarhed. Velstruktureret kode er lettere at vedligeholde, ændre og udvide.

Du er en udvikler, der har til opgave at gennemgå en andens kode og gøre den bedre. I virkelige projekter bliver kode ofte skrevet i hast, kopieret fra forskellige dele af programmet eller blot ikke designet med læsbarhed for øje. Din opgave er ikke kun at forstå koden, men også at forbedre den—gøre den renere, mere kortfattet og lettere at vedligeholde.

Lige nu udfører du et kodegennemgang. Du vil analysere et reelt stykke kode, identificere dets svage punkter og refaktorere det trin for trin ved hjælp af Stream API.

Kom godt i gang

Forestil dig, at du har en onlinebutik, og du skal identificere aktive brugere, der har afgivet mindst tre ordrer$10.000 eller mere. Dette vil hjælpe marketingteamet med at genkende de mest værdifulde kunder og tilbyde dem personlige tilbud.

Her er den oprindelige kode før refaktorering:

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 + "'}"; } }

Du har to nøgleklasser:

Order repræsenterer en ordre og indeholder et total-felt, der gemmer ordrens beløb. User repræsenterer en butikskunde med tre felter:

  • name (brugerens navn);
  • active (statusflag);
  • orders (liste over ordrer).

Hver User indeholder en liste af Order-objekter, hvilket modellerer et virkelighedsnært scenarie, hvor en kunde afgiver flere ordrer.

I main oprettes en liste af brugere, hver med deres eget sæt af ordrer. Programmet gennemløber derefter denne liste og kontrollerer, om en bruger er aktiv. Hvis ikke, springes de over.

Dernæst gennemløber programmet brugerens ordrer og tæller, hvor mange der er på $10.000 eller mere. Hvis brugeren har mindst tre kvalificerende ordrer, tilføjes de til listen premiumUsers.

Når alle brugere er behandlet, udskriver programmet de premium-brugere.

Problemer med koden

  • For mange indlejrede løkker – gør det sværere at læse og forstå;
  • Redundant kode – for mange manuelle tjek og mellemliggende variabler;
  • Mangel på deklarativ stil – koden føles som lavniveau databehandling i stedet for høj-niveau logik.

Du vil nu refaktorere denne kode trin for trin ved hjælp af Stream API for at forbedre læsbarheden, reducere redundans og gøre den mere effektiv.

Kodeomstrukturering

Første trin er at fjerne den ydre if (user.isActive()) og integrere den direkte i Stream API:

List<User> premiumUsers = users.stream()
        .filter(User::isActive)  // Keep only active users
        .toList();

Nu er koden mere deklarativ og viser tydeligt, at du filtrerer aktive brugere. Den unødvendige if-betingelse er fjernet—logikken er nu bygget direkte ind i Stream API. Dette er dog kun dataklargøring, så lad os gå videre!

Dernæst skal vi erstatte den indlejrede for-løkke (for (Order order : user.getOrders())) med et stream() inde 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 at eliminere manuel optælling er koden blevet renere og mere læsbar—nu håndterer count() dette for os, hvilket gør det muligt at arbejde med streamen uden ekstra variabler.

Endelig refaktoreret kode

Nu foreligger en fuldt refaktoreret løsning, der løser opgaven på en deklarativ og kortfattet måde:

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 + "'}"; } }

Koden er nu kortere og mere overskuelig, fordi du i stedet for en række manuelle kontroller anvender en deklarativ tilgang—med fokus på, hvad der skal gøres, frem for at beskrive hvert enkelt trin i processen. Dette eliminerer behovet for indlejrede løkker, hvilket gør koden lettere at læse og vedligeholde.

Ved at udnytte Stream API kombineres filtrering, optælling og datainnsamling problemfrit i én enkelt stream, hvilket gør koden mere udtryksfuld og effektiv.

Var alt klart?

Hvordan kan vi forbedre det?

Tak for dine kommentarer!

Sektion 4. Kapitel 1
some-alt