Collect() Samler Elementer Fra Strømmen I En Samling
Du er allerede kjent med terminale operasjoner og har til og med brukt dem i tidligere eksempler og oppgaver. Nå er det på tide å se nærmere på hvordan de fungerer. Først ut er collect()-metoden, som er en av de viktigste terminale operasjonene i Stream API.
collect()-metoden
Dette er et av de mest kraftfulle verktøyene når man arbeider med strømmer, og gjør det mulig å samle resultater i en List, Set eller Map, samt utføre komplekse grupperinger og statistiske beregninger.
Det finnes to implementasjoner av collect()-metoden—la oss utforske begge.
Bruk av collect() med funksjonelle grensesnitt
Metoden collect() i Stream API kan brukes med tre funksjonelle grensesnitt for å gi full kontroll over datainnsamling:
Supplier<R> supplier– oppretter en tom samling (R) hvor elementene skal lagres. For eksempel initialisererArrayList::newen ny liste;BiConsumer<R, ? super T> accumulator– legger til strømelementer (T) i samlingen (R). For eksempel leggerList::addtil elementer i en liste;BiConsumer<R, R> combiner– slår sammen to samlinger når parallell behandling benyttes. For eksempel kombinererList::addAlllister til én.
Alle tre komponentene samarbeider for å gi fleksibilitet i datainnsamlingen. Først oppretter supplier en tom samling som brukes til å akkumulere elementer fra strømmen. Deretter legger accumulator til hvert element etter hvert som strømmen behandles. Dette forløpet er enkelt i en sekvensiell strøm.
Når man derimot arbeider med parallelle strømmer (parallelStream()), blir prosessen mer kompleks.
Databehandlingen er delt opp på flere tråder, hvor hver tråd oppretter sin egen separate samling. Når behandlingen er ferdig, må disse individuelle samlingene slås sammen til et enkelt resultat. Det er her combiner kommer inn, og kombinerer effektivt de separate delene til én samlet samling.
Praktisk eksempel
Du jobber for en nettbutikk og har en liste over produkter. Din oppgave er å samle kun de produktene som koster mer enn $500 ved å bruke collect()-metoden med tre parametere.
Main.java
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152package 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() tar tre argumenter, som hver definerer et eget steg i innsamlingen av elementer til en liste:
-
ArrayList::new(Supplier) → oppretter en tomArrayList<Product>for å lagre resultatene; -
(list, product) -> list.add(product)(BiConsumer) → legger til hverProducti listen dersom den oppfyller filterbetingelsen (price > 500); -
ArrayList::addAll(BiConsumer) → slår sammen flere lister ved bruk av parallelle strømmer, slik at alle filtrerte produkter kombineres i én samlet liste.
Selv om den tredje parameteren hovedsakelig brukes for parallell prosessering, er den påkrevd av collect().
Bruk av collect() med Collector-grensesnittet
I tillegg til å fungere med tre funksjonelle grensesnitt, kan collect()-metoden i Stream API også brukes med forhåndsdefinerte implementasjoner av Collector-grensesnittet.
Denne tilnærmingen er mer fleksibel og praktisk ettersom den tilbyr innebygde metoder for arbeid med samlinger.
Collector<T, A, R>-grensesnittet består av flere nøkkelmetoder:
Supplier<A> supplier()– oppretter en tom beholder for å akkumulere elementer;BiConsumer<A, T> accumulator()– definerer hvordan elementer legges til i beholderen;BinaryOperator<A> combiner()– slår sammen to beholdere ved bruk av parallell prosessering;Function<A, R> finisher()– omformer beholderen til sluttresultatet.
Som du ser, er denne strukturen lik collect()-metoden som arbeider med funksjonelle grensesnitt, men den introduserer finisher()-metoden. Dette ekstra steget gir mulighet for ytterligere behandling av de innsamlede dataene før det endelige resultatet returneres—for eksempel sortering av listen før retur.
I tillegg tilbyr Collector-grensesnittet metoden characteristics(), som definerer egenskaper som bidrar til å optimalisere strømutførelsen:
Disse egenskapene hjelper Stream API med å optimalisere ytelsen. For eksempel, hvis en samling er iboende usortert, kan spesifisering av UNORDERED forhindre unødvendig sortering, noe som gjør operasjonen mer effektiv.
Praktisk eksempel
Tenk deg at du driver en nettbutikk og må behandle produktpriser før de samles inn. For eksempel ønsker du å avrunde hver pris til nærmeste hele tall, fjerne duplikater og sortere den endelige listen.
Main.java
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455package 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 starter ved å sende dataene inn i en egendefinert Collector kalt RoundedSortedCollector.
Denne collectoren samler først alle priser i et Set<Integer>, slik at duplikater automatisk fjernes. Før hver verdi legges til, avrundes prisen med Math.round(price) og konverteres til int. For eksempel vil både 1200.99 og 1200.49 bli til 1200, mens 199.99 avrundes opp til 200.
Hvis strømmen kjøres i parallellmodus, slår combiner()-metoden sammen to sett ved å legge til alle elementer fra det ene settet i det andre. Dette trinnet er avgjørende i flertrådede miljøer.
I siste steg, etter at alle priser er samlet, omdanner finisher()-metoden settet til en sortert liste. Den konverterer Set<Integer> til en strøm, bruker sorted() for å ordne verdiene i stigende rekkefølge, og samler dem deretter i en List<Integer>.
Resultatet er en sortert liste med unike, avrundede priser som kan brukes til videre beregninger eller visningsformål.
1. Hva gjør metoden collect() i Stream API?
2. Hvilken ekstra funksjonalitet gir Collector-grensesnittet sammenlignet med collect() med funksjonelle grensesnitt?
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
Collect() Samler Elementer Fra Strømmen I En Samling
Sveip for å vise menyen
Du er allerede kjent med terminale operasjoner og har til og med brukt dem i tidligere eksempler og oppgaver. Nå er det på tide å se nærmere på hvordan de fungerer. Først ut er collect()-metoden, som er en av de viktigste terminale operasjonene i Stream API.
collect()-metoden
Dette er et av de mest kraftfulle verktøyene når man arbeider med strømmer, og gjør det mulig å samle resultater i en List, Set eller Map, samt utføre komplekse grupperinger og statistiske beregninger.
Det finnes to implementasjoner av collect()-metoden—la oss utforske begge.
Bruk av collect() med funksjonelle grensesnitt
Metoden collect() i Stream API kan brukes med tre funksjonelle grensesnitt for å gi full kontroll over datainnsamling:
Supplier<R> supplier– oppretter en tom samling (R) hvor elementene skal lagres. For eksempel initialisererArrayList::newen ny liste;BiConsumer<R, ? super T> accumulator– legger til strømelementer (T) i samlingen (R). For eksempel leggerList::addtil elementer i en liste;BiConsumer<R, R> combiner– slår sammen to samlinger når parallell behandling benyttes. For eksempel kombinererList::addAlllister til én.
Alle tre komponentene samarbeider for å gi fleksibilitet i datainnsamlingen. Først oppretter supplier en tom samling som brukes til å akkumulere elementer fra strømmen. Deretter legger accumulator til hvert element etter hvert som strømmen behandles. Dette forløpet er enkelt i en sekvensiell strøm.
Når man derimot arbeider med parallelle strømmer (parallelStream()), blir prosessen mer kompleks.
Databehandlingen er delt opp på flere tråder, hvor hver tråd oppretter sin egen separate samling. Når behandlingen er ferdig, må disse individuelle samlingene slås sammen til et enkelt resultat. Det er her combiner kommer inn, og kombinerer effektivt de separate delene til én samlet samling.
Praktisk eksempel
Du jobber for en nettbutikk og har en liste over produkter. Din oppgave er å samle kun de produktene som koster mer enn $500 ved å bruke collect()-metoden med tre parametere.
Main.java
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152package 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() tar tre argumenter, som hver definerer et eget steg i innsamlingen av elementer til en liste:
-
ArrayList::new(Supplier) → oppretter en tomArrayList<Product>for å lagre resultatene; -
(list, product) -> list.add(product)(BiConsumer) → legger til hverProducti listen dersom den oppfyller filterbetingelsen (price > 500); -
ArrayList::addAll(BiConsumer) → slår sammen flere lister ved bruk av parallelle strømmer, slik at alle filtrerte produkter kombineres i én samlet liste.
Selv om den tredje parameteren hovedsakelig brukes for parallell prosessering, er den påkrevd av collect().
Bruk av collect() med Collector-grensesnittet
I tillegg til å fungere med tre funksjonelle grensesnitt, kan collect()-metoden i Stream API også brukes med forhåndsdefinerte implementasjoner av Collector-grensesnittet.
Denne tilnærmingen er mer fleksibel og praktisk ettersom den tilbyr innebygde metoder for arbeid med samlinger.
Collector<T, A, R>-grensesnittet består av flere nøkkelmetoder:
Supplier<A> supplier()– oppretter en tom beholder for å akkumulere elementer;BiConsumer<A, T> accumulator()– definerer hvordan elementer legges til i beholderen;BinaryOperator<A> combiner()– slår sammen to beholdere ved bruk av parallell prosessering;Function<A, R> finisher()– omformer beholderen til sluttresultatet.
Som du ser, er denne strukturen lik collect()-metoden som arbeider med funksjonelle grensesnitt, men den introduserer finisher()-metoden. Dette ekstra steget gir mulighet for ytterligere behandling av de innsamlede dataene før det endelige resultatet returneres—for eksempel sortering av listen før retur.
I tillegg tilbyr Collector-grensesnittet metoden characteristics(), som definerer egenskaper som bidrar til å optimalisere strømutførelsen:
Disse egenskapene hjelper Stream API med å optimalisere ytelsen. For eksempel, hvis en samling er iboende usortert, kan spesifisering av UNORDERED forhindre unødvendig sortering, noe som gjør operasjonen mer effektiv.
Praktisk eksempel
Tenk deg at du driver en nettbutikk og må behandle produktpriser før de samles inn. For eksempel ønsker du å avrunde hver pris til nærmeste hele tall, fjerne duplikater og sortere den endelige listen.
Main.java
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455package 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 starter ved å sende dataene inn i en egendefinert Collector kalt RoundedSortedCollector.
Denne collectoren samler først alle priser i et Set<Integer>, slik at duplikater automatisk fjernes. Før hver verdi legges til, avrundes prisen med Math.round(price) og konverteres til int. For eksempel vil både 1200.99 og 1200.49 bli til 1200, mens 199.99 avrundes opp til 200.
Hvis strømmen kjøres i parallellmodus, slår combiner()-metoden sammen to sett ved å legge til alle elementer fra det ene settet i det andre. Dette trinnet er avgjørende i flertrådede miljøer.
I siste steg, etter at alle priser er samlet, omdanner finisher()-metoden settet til en sortert liste. Den konverterer Set<Integer> til en strøm, bruker sorted() for å ordne verdiene i stigende rekkefølge, og samler dem deretter i en List<Integer>.
Resultatet er en sortert liste med unike, avrundede priser som kan brukes til videre beregninger eller visningsformål.
1. Hva gjør metoden collect() i Stream API?
2. Hvilken ekstra funksjonalitet gir Collector-grensesnittet sammenlignet med collect() med funksjonelle grensesnitt?
Takk for tilbakemeldingene dine!