Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Lære Collect() Indsamling af Streamelementer i en Samling | Section
Practice
Projects
Quizzes & Challenges
Quizzer
Challenges
/
Stream API i Java

bookCollect() Indsamling af Streamelementer i en Samling

Stryg for at vise menuen

Du er allerede bekendt med terminale operationer og har endda brugt dem i tidligere eksempler og øvelser. Nu er det tid til at se nærmere på, hvordan de fungerer. Først ser vi på metoden collect(), som er en af de vigtigste terminale operationer i Stream API.

Metoden collect()

Det er et af de mest kraftfulde værktøjer ved arbejde med streams, da det gør det muligt at akkumulere resultater i en List, Set eller Map, samt udføre komplekse grupperinger og statistiske beregninger.

Der findes to implementeringer af metoden collect()—lad os undersøge begge.

Brug af collect() med Funktionelle Interfaces

Metoden collect() i Stream API kan anvendes med tre funktionelle interfaces for at give fuld kontrol over datainnsamling:

  • Supplier<R> supplier – opretter en tom samling (R), hvor elementer vil blive gemt. For eksempel initialiserer ArrayList::new en ny liste;
  • BiConsumer<R, ? super T> accumulator – tilføjer stream-elementer (T) til samlingen (R). For eksempel tilføjer List::add elementer til en liste;
  • BiConsumer<R, R> combiner – sammensmelter to samlinger, når der bruges parallel behandling. For eksempel kombinerer List::addAll lister til én.

Alle tre komponenter arbejder sammen for at give fleksibilitet i datainnsamling. Først opretter supplier en tom samling, der bruges til at akkumulere elementer fra streamen. Derefter tilføjer accumulator hvert element, efterhånden som streamen behandles. Dette forløb forbliver enkelt i en sekventiel stream.

Dog bliver det mere komplekst, når der arbejdes med parallelle streams (parallelStream()).

Databehandling opdeles på flere tråde, hvor hver tråd opretter sin egen separate samling. Når behandlingen er færdig, skal disse individuelle samlinger flettes til et enkelt resultat. Her anvendes combiner, som effektivt samler de separate dele til én samlet samling.

Praktisk eksempel

Du arbejder for en onlinebutik og har en liste over produkter. Din opgave er at indsamle kun de produkter, der koster mere end $500, ved hjælp af collect()-metoden med tre parametre.

Main.java

Main.java

copy
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152
package com.example; import java.util.ArrayList; import java.util.List; public class Main { public static void main(String[] args) { // Initial list of products List<Product> productList = List.of( new Product("Laptop", 1200.99), new Product("Phone", 599.49), new Product("Headphones", 199.99), new Product("Monitor", 299.99), new Product("Tablet", 699.99) ); // Filtering and collecting products over $500 using `collect()` List<Product> expensiveProducts = productList.parallelStream() .filter(product -> product.getPrice() > 500) // Keep only expensive products .collect( ArrayList::new, // Create a new list (list, product) -> list.add(product), // Add each product to the list ArrayList::addAll // Merge lists (if the stream is parallel) ); // Print the result System.out.print("Products over $500: " + expensiveProducts); } } class Product { private String name; private double price; Product(String name, double price) { this.name = name; this.price = price; } public String getName() { return name; } public double getPrice() { return price; } @Override public String toString() { return name + " ($" + price + ")"; } }

Metoden collect() tager tre argumenter, som hver definerer et trin i indsamlingen af elementer til en liste:

  • ArrayList::new (Supplier) → opretter en tom ArrayList<Product> til at gemme resultaterne;

  • (list, product) -> list.add(product) (BiConsumer) → tilføjer hver Product til listen, hvis den opfylder filterbetingelsen (price > 500);

  • ArrayList::addAll (BiConsumer) → samler flere lister ved brug af parallelle streams, så alle filtrerede produkter kombineres i en enkelt liste.

Selvom den tredje parameter primært bruges til parallel behandling, er den påkrævet af collect().

Brug af collect() med Collector-interfacet

Ud over at arbejde med tre funktionelle interfaces kan metoden collect() i Stream API også anvendes med foruddefinerede implementeringer af Collector-interfacet.

Denne tilgang er mere fleksibel og praktisk, da den tilbyder indbyggede metoder til at arbejde med samlinger.

Collector<T, A, R>-interfacet består af flere centrale metoder:

  • Supplier<A> supplier() – opretter en tom beholder til at akkumulere elementer;
  • BiConsumer<A, T> accumulator() – definerer, hvordan elementer tilføjes til beholderen;
  • BinaryOperator<A> combiner() – samler to beholdere ved parallel behandling;
  • Function<A, R> finisher() – omdanner beholderen til det endelige resultat.

Som du kan se, ligner denne struktur den collect()-metode, der arbejder med funktionelle grænseflader, men den introducerer finisher()-metoden. Dette ekstra trin muliggør yderligere behandling af de indsamlede data, før det endelige resultat returneres—for eksempel sortering af listen inden returnering.

Derudover tilbyder Collector-grænsefladen metoden characteristics(), som definerer egenskaber, der hjælper med at optimere stream-udførelse:

Disse egenskaber hjælper Stream API med at optimere ydelsen. For eksempel, hvis en samling er iboende uordnet, kan angivelse af UNORDERED forhindre unødvendig sortering, hvilket gør operationen mere effektiv.

Praktisk eksempel

Forestil dig, at du driver en onlinebutik og skal behandle produktpriser inden indsamling. For eksempel ønsker du at afrunde hver pris til nærmeste hele tal, fjerne dubletter og sortere den endelige liste.

Main.java

Main.java

copy
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455
package com.example; import java.util.*; import java.util.function.*; import java.util.stream.Collector; import java.util.stream.Stream; public class Main { public static void main(String[] args) { List<Double> prices = List.of(1200.99, 599.49, 199.99, 599.49, 1200.49, 200.0); // Using a custom `Collector` to round prices, remove duplicates, and sort List<Integer> processedPrices = prices.parallelStream() .collect(new RoundedSortedCollector()); System.out.println("Processed product prices: " + processedPrices); } } // Custom `Collector` that rounds prices, removes duplicates, and sorts them class RoundedSortedCollector implements Collector<Double, Set<Integer>, List<Integer>> { @Override public Supplier<Set<Integer>> supplier() { // Creates a `HashSet` to store unique rounded values return HashSet::new; } @Override public BiConsumer<Set<Integer>, Double> accumulator() { // Rounds price and adds to the set return (set, price) -> set.add((int) Math.round(price)); } @Override public BinaryOperator<Set<Integer>> combiner() { return (set1, set2) -> { set1.addAll(set2); // Merges two sets return set1; }; } @Override public Function<Set<Integer>, List<Integer>> finisher() { return set -> set.stream() .sorted() // Sorts the final list .toList(); } @Override public Set<Characteristics> characteristics() { // Order is not important during accumulation return Set.of(Characteristics.UNORDERED); } }

Databehandlingen påbegyndes ved at sende den ind i en brugerdefineret Collector kaldet RoundedSortedCollector.

Denne collector akkumulerer først alle priser i et Set<Integer>, hvilket sikrer, at dubletter automatisk fjernes. Før hver værdi tilføjes, afrundes prisen ved hjælp af Math.round(price) og konverteres til en int. For eksempel vil både 1200.99 og 1200.49 blive til 1200, mens 199.99 afrundes til 200.

Hvis streamen kører i paralleltilstand, sammenfletter combiner()-metoden to sæt ved at tilføje alle elementer fra det ene sæt til det andet. Dette trin er afgørende i multitrådede miljøer.

I den afsluttende fase, efter at alle priser er indsamlet, omdanner finisher()-metoden sættet til en sorteret liste. Den konverterer Set<Integer> til en stream, anvender sorted() for at arrangere værdierne i stigende rækkefølge, og samler dem derefter i en List<Integer>.

Resultatet er en sorteret liste af unikke, afrundede priser, som kan anvendes til yderligere beregninger eller visningsformål.

1. Hvad gør collect()-metoden i Stream API?

2. Hvilken yderligere funktionalitet tilbyder Collector-interfacet sammenlignet med collect() med funktionelle interfaces?

question mark

Hvad gør collect()-metoden i Stream API?

Select the correct answer

question mark

Hvilken yderligere funktionalitet tilbyder Collector-interfacet sammenlignet med collect() med funktionelle interfaces?

Select the correct answer

Var alt klart?

Hvordan kan vi forbedre det?

Tak for dine kommentarer!

Sektion 1. Kapitel 27

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

Sektion 1. Kapitel 27
some-alt