Behandling af Elementer med forEach()-Metoden
Du er allerede bekendt med metoden forEach(), da du har brugt den i praksis til at udskrive hvert element i en samling til konsollen. Lad os se nærmere på den og undersøge dens implementeringer.
Den giver en bekvem måde at behandle data på i en funktionel stil. Det er dog vigtigt at bemærke, at behandlingsrækkefølgen afhænger af stream-typen og den anvendte metode.
Der findes to implementeringer af metoden forEach() i Stream API. Lad os gennemgå dem én ad gangen.
forEach-metode
Udfører en handling på hvert element, men behandlingsrækkefølgen er ikke garanteret i parallelle streams.
void forEach(Consumer<? super T> action)
Metoden forEach() tager en Consumer<T> som argument—et funktionelt interface, der definerer en operation for hvert element i strømmen. Den anvendes ofte til logning, udskrivning eller udførelse af sideeffekter.
Praktisk eksempel
I en onlinebutik skal brugere modtage notifikationer om personlige rabatter. Da rækkefølgen er uden betydning, anvendes forEach() med en parallel strøm for hurtigere udførelse.
Main.java
1234567891011121314151617181920212223package com.example; import java.util.List; import java.util.stream.Stream; public class Main { public static void main(String[] args) { List<String> customers = List.of( "alice@example.com", "bob@example.com", "charlie@example.com" ); // Parallel stream for faster processing Stream<String> customerStream = customers.parallelStream(); customerStream.forEach(email -> sendDiscountEmail(email)); } private static void sendDiscountEmail(String email) { System.out.println("Sending discount email to: " + email); // Simulating email sending process } }
Denne kode simulerer afsendelse af personlige rabat-e-mails til kunder. Da parallelStream() anvendes, sendes e-mails i vilkårlig rækkefølge for forbedret hastighed. Metoden forEach() anvender den angivne handling på hver e-mail.
forEachOrdered-metoden
Udfører en handling, mens rækkefølgen af elementer bevares, selv i parallelle streams.
void forEachOrdered(Consumer<? super T> action)
Ligesom forEach accepterer denne metode også en Consumer<T>, men den sikrer, at elementer behandles i samme rækkefølge, som de vises i den oprindelige stream. Dette er nyttigt, når det er afgørende at bevare sekvensen.
Praktisk eksempel
Forestil dig et betalingssystem, hvor hver transaktion skal behandles i præcis den rækkefølge, den ankommer. Hvis betalinger håndteres i forkert rækkefølge, kan det føre til fejl, såsom forkerte saldoopgørelser.
Main.java
123456789101112131415161718192021package com.example; import java.util.List; import java.util.stream.Stream; public class Main { public static void main(String[] args) { List<String> payments = List.of( "Payment #5001 - $100", "Payment #5002 - $250", "Payment #5003 - $75" ); Stream<String> paymentStream = payments.parallelStream(); paymentStream.forEachOrdered(payment -> processPayment(payment)); } private static void processPayment(String payment) { System.out.println("Processing payment: " + payment); } }
Denne kode simulerer et betalingsbehandlingssystem, hvor transaktioner skal håndteres i den rækkefølge, de ankommer. Anvendelsen af parallelStream() øger ydelsen, men forEachOrdered() sikrer, at rækkefølgen forbliver intakt.
Ydelsessammenligning: forEach() vs. forEachOrdered()
Her måles hvor meget hurtigere forEach() udføres sammenlignet med forEachOrdered() ved brug af parallelle streams. Til dette oprettes en liste med 10 millioner elementer, som behandles med begge metoder ved at beregne kvadratroden af hvert tal, og udførelsestiden registreres.
Main.java
12345678910111213141516171819202122232425262728293031package com.example; import java.util.List; import java.util.stream.IntStream; import java.util.ArrayList; public class Main { public static void main(String[] args) { List<Integer> numbers = new ArrayList<>(); IntStream.range(0, 10_000_000).forEach(numbers::add); // Create a list with 10 million elements // Measure execution time of `forEach()` long startTime = System.nanoTime(); numbers.parallelStream().forEach(num -> process(num)); long forEachTime = System.nanoTime() - startTime; // Measure execution time of `forEachOrdered()` startTime = System.nanoTime(); numbers.parallelStream().forEachOrdered(num -> process(num)); long forEachOrderedTime = System.nanoTime() - startTime; // Print results System.out.println("forEach execution time: " + forEachTime / 1_000_000 + " ms"); System.out.println("forEachOrdered execution time: " + forEachOrderedTime / 1_000_000 + " ms"); } private static void process(int num) { // Simulate workload Math.sqrt(num); } }
Metoden forEach() behandler elementer uden at bevare rækkefølgen, hvilket gør det muligt for streamen frit at fordele opgaver på tilgængelige processor-kerner. Dette maksimerer ydelsen, da hver tråd kan vælge elementer i vilkårlig rækkefølge og behandle dem parallelt uden begrænsninger.
Metoden forEachOrdered() bevarer den oprindelige rækkefølge af elementer, hvilket kræver yderligere synkronisering. I en parallelt stream opdeles elementerne først i blokke til behandling, men deres resultater skal derefter samles i den korrekte rækkefølge, før de sendes videre til behandlingsmetoden.
1. Hvilket funktionelt interface accepterer forEach-metoden?
2. Hvilket output kan denne kode producere?
Tak for dine kommentarer!
Spørg AI
Spørg AI
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
Behandling af Elementer med forEach()-Metoden
Stryg for at vise menuen
Du er allerede bekendt med metoden forEach(), da du har brugt den i praksis til at udskrive hvert element i en samling til konsollen. Lad os se nærmere på den og undersøge dens implementeringer.
Den giver en bekvem måde at behandle data på i en funktionel stil. Det er dog vigtigt at bemærke, at behandlingsrækkefølgen afhænger af stream-typen og den anvendte metode.
Der findes to implementeringer af metoden forEach() i Stream API. Lad os gennemgå dem én ad gangen.
forEach-metode
Udfører en handling på hvert element, men behandlingsrækkefølgen er ikke garanteret i parallelle streams.
void forEach(Consumer<? super T> action)
Metoden forEach() tager en Consumer<T> som argument—et funktionelt interface, der definerer en operation for hvert element i strømmen. Den anvendes ofte til logning, udskrivning eller udførelse af sideeffekter.
Praktisk eksempel
I en onlinebutik skal brugere modtage notifikationer om personlige rabatter. Da rækkefølgen er uden betydning, anvendes forEach() med en parallel strøm for hurtigere udførelse.
Main.java
1234567891011121314151617181920212223package com.example; import java.util.List; import java.util.stream.Stream; public class Main { public static void main(String[] args) { List<String> customers = List.of( "alice@example.com", "bob@example.com", "charlie@example.com" ); // Parallel stream for faster processing Stream<String> customerStream = customers.parallelStream(); customerStream.forEach(email -> sendDiscountEmail(email)); } private static void sendDiscountEmail(String email) { System.out.println("Sending discount email to: " + email); // Simulating email sending process } }
Denne kode simulerer afsendelse af personlige rabat-e-mails til kunder. Da parallelStream() anvendes, sendes e-mails i vilkårlig rækkefølge for forbedret hastighed. Metoden forEach() anvender den angivne handling på hver e-mail.
forEachOrdered-metoden
Udfører en handling, mens rækkefølgen af elementer bevares, selv i parallelle streams.
void forEachOrdered(Consumer<? super T> action)
Ligesom forEach accepterer denne metode også en Consumer<T>, men den sikrer, at elementer behandles i samme rækkefølge, som de vises i den oprindelige stream. Dette er nyttigt, når det er afgørende at bevare sekvensen.
Praktisk eksempel
Forestil dig et betalingssystem, hvor hver transaktion skal behandles i præcis den rækkefølge, den ankommer. Hvis betalinger håndteres i forkert rækkefølge, kan det føre til fejl, såsom forkerte saldoopgørelser.
Main.java
123456789101112131415161718192021package com.example; import java.util.List; import java.util.stream.Stream; public class Main { public static void main(String[] args) { List<String> payments = List.of( "Payment #5001 - $100", "Payment #5002 - $250", "Payment #5003 - $75" ); Stream<String> paymentStream = payments.parallelStream(); paymentStream.forEachOrdered(payment -> processPayment(payment)); } private static void processPayment(String payment) { System.out.println("Processing payment: " + payment); } }
Denne kode simulerer et betalingsbehandlingssystem, hvor transaktioner skal håndteres i den rækkefølge, de ankommer. Anvendelsen af parallelStream() øger ydelsen, men forEachOrdered() sikrer, at rækkefølgen forbliver intakt.
Ydelsessammenligning: forEach() vs. forEachOrdered()
Her måles hvor meget hurtigere forEach() udføres sammenlignet med forEachOrdered() ved brug af parallelle streams. Til dette oprettes en liste med 10 millioner elementer, som behandles med begge metoder ved at beregne kvadratroden af hvert tal, og udførelsestiden registreres.
Main.java
12345678910111213141516171819202122232425262728293031package com.example; import java.util.List; import java.util.stream.IntStream; import java.util.ArrayList; public class Main { public static void main(String[] args) { List<Integer> numbers = new ArrayList<>(); IntStream.range(0, 10_000_000).forEach(numbers::add); // Create a list with 10 million elements // Measure execution time of `forEach()` long startTime = System.nanoTime(); numbers.parallelStream().forEach(num -> process(num)); long forEachTime = System.nanoTime() - startTime; // Measure execution time of `forEachOrdered()` startTime = System.nanoTime(); numbers.parallelStream().forEachOrdered(num -> process(num)); long forEachOrderedTime = System.nanoTime() - startTime; // Print results System.out.println("forEach execution time: " + forEachTime / 1_000_000 + " ms"); System.out.println("forEachOrdered execution time: " + forEachOrderedTime / 1_000_000 + " ms"); } private static void process(int num) { // Simulate workload Math.sqrt(num); } }
Metoden forEach() behandler elementer uden at bevare rækkefølgen, hvilket gør det muligt for streamen frit at fordele opgaver på tilgængelige processor-kerner. Dette maksimerer ydelsen, da hver tråd kan vælge elementer i vilkårlig rækkefølge og behandle dem parallelt uden begrænsninger.
Metoden forEachOrdered() bevarer den oprindelige rækkefølge af elementer, hvilket kræver yderligere synkronisering. I en parallelt stream opdeles elementerne først i blokke til behandling, men deres resultater skal derefter samles i den korrekte rækkefølge, før de sendes videre til behandlingsmetoden.
1. Hvilket funktionelt interface accepterer forEach-metoden?
2. Hvilket output kan denne kode producere?
Tak for dine kommentarer!