Stream-API i Java
Det finnes ulike måter å behandle data på i Java – løkker, metoder og forskjellige algoritmer. Men i Java 8 ble et svært kraftig verktøy introdusert – Stream API.
Enkelt forklart er Stream API en måte å arbeide raskt og enkelt med en datastrøm. I vårt tilfelle er denne datastrømmen representert av samlinger. Stream API har noen begreper. Her er de viktigste.
Hovedbegreper
-
Stream: representerer en sekvens av dataelementer som kan behandles;
-
Intermediære operasjoner: operasjoner som oppretter en ny stream etter utførelse. Eksempler:
filter,map,distinct,sorted; -
Terminale operasjoner: operasjoner som fullfører behandlingen av streamen og returnerer et resultat. Eksempler:
collect,forEach,count,reduce; -
Parallellstrømmer: muliggjør parallell behandling av data. Metodene
parallel()ogparallelStream()brukes for å opprette parallellstrømmer.
Nok teori, la oss begynne å kode!
En strøm erklæres ved å bruke en metode på samlingen du ønsker å gjøre om til en strøm:
Main.java
12List<String> strings = Arrays.asList("a", "b", "c"); Stream<String> stream = strings.stream();
Med stream()-metoden fikk vi en strøm av strenger. For å begynne å arbeide med strømmen, må vi forstå hva lambda-uttrykk er, siden strømmens metoder hovedsakelig benytter disse.
Lambda-uttrykk
Lambda-uttrykk ble introdusert i Java 8, og de representerer en forenklet måte å lage anonyme funksjoner i Java. Vi har ikke gått gjennom anonyme funksjoner tidligere, da de ikke har vært spesielt nødvendige, men nå skal vi bli kjent med dem gjennom lambda-uttrykk.
Syntaks for lambda-uttrykk:
Den generelle syntaksen for lambda-uttrykk i Java ser slik ut:
Example.java
123(parameters) -> expression // or (parameters) -> { statements; }
-
Parametere: dette er en parameterliste som kan være tom eller inneholde én eller flere parametere;
-
Pil: representert ved symbolet
->, som skiller parameterne fra kroppen til lambda-uttrykket; -
Uttrykk eller setninger: dette er funksjonens kropp, som inneholder et uttrykk eller en blokk med setninger.
Her er et eksempel på et lambda-uttrykk som representerer en enkel funksjon som legger sammen to tall:
Example.java
12345678910// Traditional way MathOperation addition = new MathOperation() { @Override public int operate(int a, int b) { return a + b; } }; // Using a lambda expression MathOperation addition = (int a, int b) -> a + b;
La oss se nærmere på hva som faktisk skjer i koden over og hvordan vi bruker lambda-uttrykk:
Main.java
1234567891011121314package com.example; // Functional interface with a single abstract method interface MyMathOperation { int operate(int a, int b); } public class Main { public static void main(String[] args) { // Using a lambda expression to implement the interface MyMathOperation addition = (a, b) -> a + b; System.out.println("Sum: " + addition.operate(5, 3)); } }
I koden ovenfor:
Opprettet et funksjonelt grensesnitt MyMathOperation med én abstrakt metode operate.
Brukte et lambda-uttrykk for å implementere denne metoden, som utfører addisjon av to tall.
Resultatet av addisjonen ble skrevet ut.
Det er forståelig at det kan være utfordrende å forstå hva som skjer i denne koden foreløpig, men la oss gå tilbake til Stream API, hvor lambda-uttrykk ofte brukes, og prøve å forstå hvordan de benyttes i praksis.
Som du husker, opprettet vi tidligere en stream av strenger fra en liste med strenger. Nå skal vi bruke stream-metoder for å gjøre hver streng i denne strømmen til store bokstaver:
Main.java
12345678910111213package com.example; import java.util.Arrays; import java.util.List; import java.util.stream.Stream; public class Main { public static void main(String[] args) { List<String> strings = Arrays.asList("a", "b", "c"); Stream<String> stream = strings.stream(); stream.map(e -> e.toUpperCase()).toList(); } }
I koden ovenfor brukte vi et lambda-uttrykk og to metoder: map() og toList(). Dersom det er åpenbart hva metoden toList() gjør, så endrer map()-metoden hver enkelt element i strømmen i henhold til det angitte lambda-uttrykket.
La oss se nærmere på hvordan lambda-uttrykket fungerer her:
Metoden map() anvender toUpperCase()-metoden på hvert element i strømmen. Vi definerte elementet i denne strømmen som e og, ved hjelp av lambda-uttrykket, instruerte vi programmet til å anvende denne metoden på hvert element.
Men dette er ikke slutten, fordi vi har brukt en mellomliggende operasjon. Dette betyr at operasjonene på strømmen ikke er fullført ennå. For å fullføre arbeidet med strømmen, må vi bruke en terminal operasjon, som avslutter operasjonene på strømmen og returnerer en spesifikk verdi. For eksempel kan du bruke metoden toList(), og den modifiserte strømmen vil konverteres til en liste.
For eksempel:
Main.java
1234567891011121314package com.example; import java.util.Arrays; import java.util.List; import java.util.stream.Stream; public class Main { public static void main(String[] args) { List<String> strings = Arrays.asList("a", "b", "c"); Stream<String> stream = strings.stream(); List<String> list = stream.map(e -> e.toUpperCase()).toList(); System.out.println(list); } }
La oss se nærmere på mulige mellomliggende operasjoner i en stream.
Mellomliggende operasjoner
Metoden map() – du er allerede kjent med denne metoden; den utfører operasjoner spesifisert av lambda-uttrykket på hvert element i streamen.
For eksempel kan vi bruke metoden substring() på hvert element i en stream av strenger:
Main.java
123456789101112131415package com.example; import java.util.Arrays; import java.util.List; import java.util.stream.Stream; public class Main { public static void main(String[] args) { List<String> strings = Arrays.asList("Unlock", "Infinity", "with", "Codefinity"); System.out.println("List of strings: " + strings); Stream<String> stream = strings.stream(); List<String> list = stream.map(e -> e.substring(1, 4)).toList(); System.out.println("Modified list: " + list); } }
Metoden filter() tar et lambda-uttrykk med en betingelse som brukes til å filtrere strømmen. Det vil si at alle elementer som oppfyller betingelsen vil forbli i strømmen, mens elementer som ikke oppfyller betingelsen vil bli fjernet fra strømmen. Vi kan endre strømmen slik at kun elementer med lengde større enn 5 beholdes:
Main.java
12345678910111213141516package com.example; import java.util.Arrays; import java.util.List; import java.util.stream.Stream; public class Main { public static void main(String[] args) { List<String> strings = Arrays.asList("Unlock", "Infinity", "with", "Codefinity"); System.out.println("List of strings: " + strings); Stream<String> stream = strings.stream(); stream = stream.filter(e -> e.length() > 5); List<String> list = stream.map(e -> e.substring(1, 4)).toList(); System.out.println("Modified list: " + list); } }
Ved å bruke filter()-metoden fjerner vi strengen "with" fra strømmen fordi dette ordet har færre enn 5 tegn.
Det er også mulig å bruke mellomliggende operasjoner flere ganger etter hverandre.
For eksempel kan vi forenkle koden ovenfor noe:
Main.java
12345678910111213141516package com.example; import java.util.Arrays; import java.util.List; public class Main { public static void main(String[] args) { List<String> strings = Arrays.asList("Unlock", "Infinity", "with", "Codefinity"); System.out.println("List of strings: " + strings); List<String> list = strings.stream() .filter(e -> e.length() > 5) .map(e -> e.substring(1, 4)) .toList(); System.out.println("Modified list: " + list); } }
Ved sammenkobling av flere strømmetoder anbefales det å plassere hver metode på en ny linje for å forbedre lesbarheten i koden betydelig.
Metoden flatMap() transformerer hvert element i en strøm til en ny strøm og kombinerer resultatene til én enkelt strøm. Med andre ord, med denne metoden kan vi dele opp strømmen i flere strømmer, som deretter slås sammen til én strøm. For eksempel, du har en liste med strenger der hver streng kan inneholde mer enn ett ord, som en liste med for- og etternavn. Og du trenger å gjøre første bokstav i hvert av disse ordene stor:
Main.java
123456789101112131415161718192021222324package com.example; import java.util.Arrays; import java.util.List; public class Main { public static void main(String[] args) { List<String> users = Arrays.asList("Ethan Johnson", "Olivia smith", "mason davis", "Ava taylor", "logan brown", "Emma Anderson", "jackson miller"); System.out.println("List of users: " + users); List<String> list = users.stream() .flatMap(e -> Arrays.stream(e.split(" "))) .map(e -> capitalizeFirstLetter(e)) .toList(); System.out.println("List with capitalized names and surnames: " + list); } private static String capitalizeFirstLetter(String word) { if (word == null || word.isEmpty()) { return word; } return Character.toUpperCase(word.charAt(0)) + word.substring(1); } }
I koden over skrev vi en egen privat metode som gjør første bokstav i et ord stor, og brukte denne metoden i map()-metoden sammen med et lambda-uttrykk.
Merk at ved å bruke flatMap-metoden deler vi opp hvert element i strømmen til ulike strømmer ved å bruke Arrays.stream(e.split(" "))-metoden. Fordi split()-metoden returnerer et array, må vi bruke Arrays.stream()-metoden for å dele opp dette arrayet i strømmer.
Deretter blir alle disse strømmene slått sammen til én strøm, og etterpå bruker vi metoden vi skrev. Nå har vi alle fornavn og etternavn til brukere med stor forbokstav.
Vet du hva som hadde vært kult?
Hvis vi legger disse fornavnene og etternavnene inn i en HashMap, hvor nøkkelen er etternavnet og verdien er fornavnet.
La oss implementere dette i koden:
Main.java
12345678910111213141516171819202122232425262728293031323334package com.example; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; public class Main { public static void main(String[] args) { List<String> users = Arrays.asList("Ethan Johnson", "Olivia smith", "mason davis", "Ava taylor", "logan brown", "Emma Anderson", "jackson miller"); System.out.println("List of users: " + users); List<String> list = users.stream() .flatMap(e -> Arrays.stream(e.split(" "))) .map(e -> capitalizeFirstLetter(e)) .toList(); System.out.println("List with capitalized names and surnames: " + list); Map<String, String> usersKeyValue = new HashMap<>(); for (int i = 0; i < list.size() - 1; i+=2) { String name = list.get(i); String surname = list.get(i + 1); usersKeyValue.put(surname, name); } System.out.println("Map with surnames as keys and names as values: " + usersKeyValue); } private static String capitalizeFirstLetter(String word) { if (word == null || word.isEmpty()) { return word; } return Character.toUpperCase(word.charAt(0)) + word.substring(1); } }
Med en enkel løkke lagret vi fornavn og etternavn i variabler og deretter i kartet. Legg merke til hvordan løkken fungerer. Vi øker variabelen i med 2 i hver iterasjon fordi vi må hoppe over etternavnet når vi allerede har registrert det.
- Metoden
distinct()fjerner duplikater fra strømmen. Generelt kan dette være nyttig hvis du trenger unike elementer i strømmen eller hvis du vil raskt eliminere duplikater fra en liste. Dette kan enkelt oppnås med følgende konstruksjon:
list.stream().distinct().toList()
-
Metoden
sortedsorterer alle elementene i strømmen i naturlig rekkefølge, fra det minste til det største tallet eller i alfabetisk rekkefølge. Dette kan også være nyttig hvis du trenger en sortert strøm eller hvis du raskt må sortere en liste; -
Metoden
skip(n)hopper over de førstenelementene i strømmen. Dette kan være nyttig når du arbeider med tekstfiler, der de første n linjene for eksempel kan være metadata eller en filbeskrivelse. Det er også verdt å nevne metodenlimit(n), som generelt begrenset antall elementer i strømmen. Selv om vi oppretter en strøm med 1000 elementer og deretter brukerlimit(200), vil strømmen kun inneholde de første 200 elementene.
Main.java
123456789101112package com.example; import java.util.Arrays; import java.util.List; public class Main { public static void main(String[] args) { List<Integer> example = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); example = example.stream().skip(3).limit(5).toList(); System.out.println("List: " + example); } }
Dette er de viktigste mellomliggende metodene du trenger å bruke. Du kan utforske resten av metodene ved å se i lenken til den offisielle Java-dokumentasjonen. La oss gå videre til terminalmetoder.
Terminalmetoder
-
Terminalmetoden du allerede kjenner til er
toList(). Den konverterer strømmen til en liste og returnerer den. Med andre ord kan du direkte tilordne denne strømmen med metoder til en liste. Denne metoden ble introdusert i Java 17 og fungerer som en erstatning for den mer komplekse konstruksjonencollect(Collectors.toList()); -
Metoden
collect()konverterer også strømmen til en spesifikk datastruktur. Den bruker, som parameter, en metode fraCollectors-grensesnittet. Dette grensesnittet har metoder somtoList(),toSet()ogtoCollection(). For eksempel:
Main.java
123456789101112131415package com.example; import java.util.Arrays; import java.util.List; import java.util.Set; import java.util.stream.Collectors; public class Main { public static void main(String[] args) { List<Integer> example = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); Set<Integer> integerSet = example.stream().collect(Collectors.toSet()); System.out.println("List: " + example); System.out.println("Set: " + integerSet); } }
Metoden forEach() tar et lambda-uttrykk og utfører en spesifikk handling for hvert element i strømmen.
For eksempel:
Main.java
1234567891011package com.example; import java.util.Arrays; import java.util.List; public class Main { public static void main(String[] args) { List<Integer> example = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); example.stream().forEach(e -> System.out.println(e + 1)); } }
Forskjellen mellom denne metoden og map-metoden er at denne metoden er terminal, og etter den kan du ikke kalle andre metoder.
Dette er alle grunnleggende metoder for arbeid med streams. Det er et komplekst emne, og du forstår det kanskje ikke med en gang. Likevel er det et tema som mestres gjennom praksis. I de kommende praksiskapitlene med streams vil du få mange muligheter til å arbeide med dem, da det er en svært praktisk og effektiv måte å håndtere lister og datastrukturer på!
1. Hva er hovedformålet med Stream API i Java?
2. Hvilken av følgende er en terminaloperasjon i Stream API?
3. Hva gjør map-operasjonen i Stream API?
4. Hvordan skiller flatMap-operasjonen seg fra map i Stream API?
5. Hva gjør filter-operasjonen i Stream API?
6. Hva er formålet med forEach-operasjonen i Stream API?
7. Hvilken av følgende er en mellomliggende operasjon i Stream API?
8. Hvordan brukes limit-operasjonen i Stream API?
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
Fantastisk!
Completion rate forbedret til 4
Stream-API i Java
Sveip for å vise menyen
Det finnes ulike måter å behandle data på i Java – løkker, metoder og forskjellige algoritmer. Men i Java 8 ble et svært kraftig verktøy introdusert – Stream API.
Enkelt forklart er Stream API en måte å arbeide raskt og enkelt med en datastrøm. I vårt tilfelle er denne datastrømmen representert av samlinger. Stream API har noen begreper. Her er de viktigste.
Hovedbegreper
-
Stream: representerer en sekvens av dataelementer som kan behandles;
-
Intermediære operasjoner: operasjoner som oppretter en ny stream etter utførelse. Eksempler:
filter,map,distinct,sorted; -
Terminale operasjoner: operasjoner som fullfører behandlingen av streamen og returnerer et resultat. Eksempler:
collect,forEach,count,reduce; -
Parallellstrømmer: muliggjør parallell behandling av data. Metodene
parallel()ogparallelStream()brukes for å opprette parallellstrømmer.
Nok teori, la oss begynne å kode!
En strøm erklæres ved å bruke en metode på samlingen du ønsker å gjøre om til en strøm:
Main.java
12List<String> strings = Arrays.asList("a", "b", "c"); Stream<String> stream = strings.stream();
Med stream()-metoden fikk vi en strøm av strenger. For å begynne å arbeide med strømmen, må vi forstå hva lambda-uttrykk er, siden strømmens metoder hovedsakelig benytter disse.
Lambda-uttrykk
Lambda-uttrykk ble introdusert i Java 8, og de representerer en forenklet måte å lage anonyme funksjoner i Java. Vi har ikke gått gjennom anonyme funksjoner tidligere, da de ikke har vært spesielt nødvendige, men nå skal vi bli kjent med dem gjennom lambda-uttrykk.
Syntaks for lambda-uttrykk:
Den generelle syntaksen for lambda-uttrykk i Java ser slik ut:
Example.java
123(parameters) -> expression // or (parameters) -> { statements; }
-
Parametere: dette er en parameterliste som kan være tom eller inneholde én eller flere parametere;
-
Pil: representert ved symbolet
->, som skiller parameterne fra kroppen til lambda-uttrykket; -
Uttrykk eller setninger: dette er funksjonens kropp, som inneholder et uttrykk eller en blokk med setninger.
Her er et eksempel på et lambda-uttrykk som representerer en enkel funksjon som legger sammen to tall:
Example.java
12345678910// Traditional way MathOperation addition = new MathOperation() { @Override public int operate(int a, int b) { return a + b; } }; // Using a lambda expression MathOperation addition = (int a, int b) -> a + b;
La oss se nærmere på hva som faktisk skjer i koden over og hvordan vi bruker lambda-uttrykk:
Main.java
1234567891011121314package com.example; // Functional interface with a single abstract method interface MyMathOperation { int operate(int a, int b); } public class Main { public static void main(String[] args) { // Using a lambda expression to implement the interface MyMathOperation addition = (a, b) -> a + b; System.out.println("Sum: " + addition.operate(5, 3)); } }
I koden ovenfor:
Opprettet et funksjonelt grensesnitt MyMathOperation med én abstrakt metode operate.
Brukte et lambda-uttrykk for å implementere denne metoden, som utfører addisjon av to tall.
Resultatet av addisjonen ble skrevet ut.
Det er forståelig at det kan være utfordrende å forstå hva som skjer i denne koden foreløpig, men la oss gå tilbake til Stream API, hvor lambda-uttrykk ofte brukes, og prøve å forstå hvordan de benyttes i praksis.
Som du husker, opprettet vi tidligere en stream av strenger fra en liste med strenger. Nå skal vi bruke stream-metoder for å gjøre hver streng i denne strømmen til store bokstaver:
Main.java
12345678910111213package com.example; import java.util.Arrays; import java.util.List; import java.util.stream.Stream; public class Main { public static void main(String[] args) { List<String> strings = Arrays.asList("a", "b", "c"); Stream<String> stream = strings.stream(); stream.map(e -> e.toUpperCase()).toList(); } }
I koden ovenfor brukte vi et lambda-uttrykk og to metoder: map() og toList(). Dersom det er åpenbart hva metoden toList() gjør, så endrer map()-metoden hver enkelt element i strømmen i henhold til det angitte lambda-uttrykket.
La oss se nærmere på hvordan lambda-uttrykket fungerer her:
Metoden map() anvender toUpperCase()-metoden på hvert element i strømmen. Vi definerte elementet i denne strømmen som e og, ved hjelp av lambda-uttrykket, instruerte vi programmet til å anvende denne metoden på hvert element.
Men dette er ikke slutten, fordi vi har brukt en mellomliggende operasjon. Dette betyr at operasjonene på strømmen ikke er fullført ennå. For å fullføre arbeidet med strømmen, må vi bruke en terminal operasjon, som avslutter operasjonene på strømmen og returnerer en spesifikk verdi. For eksempel kan du bruke metoden toList(), og den modifiserte strømmen vil konverteres til en liste.
For eksempel:
Main.java
1234567891011121314package com.example; import java.util.Arrays; import java.util.List; import java.util.stream.Stream; public class Main { public static void main(String[] args) { List<String> strings = Arrays.asList("a", "b", "c"); Stream<String> stream = strings.stream(); List<String> list = stream.map(e -> e.toUpperCase()).toList(); System.out.println(list); } }
La oss se nærmere på mulige mellomliggende operasjoner i en stream.
Mellomliggende operasjoner
Metoden map() – du er allerede kjent med denne metoden; den utfører operasjoner spesifisert av lambda-uttrykket på hvert element i streamen.
For eksempel kan vi bruke metoden substring() på hvert element i en stream av strenger:
Main.java
123456789101112131415package com.example; import java.util.Arrays; import java.util.List; import java.util.stream.Stream; public class Main { public static void main(String[] args) { List<String> strings = Arrays.asList("Unlock", "Infinity", "with", "Codefinity"); System.out.println("List of strings: " + strings); Stream<String> stream = strings.stream(); List<String> list = stream.map(e -> e.substring(1, 4)).toList(); System.out.println("Modified list: " + list); } }
Metoden filter() tar et lambda-uttrykk med en betingelse som brukes til å filtrere strømmen. Det vil si at alle elementer som oppfyller betingelsen vil forbli i strømmen, mens elementer som ikke oppfyller betingelsen vil bli fjernet fra strømmen. Vi kan endre strømmen slik at kun elementer med lengde større enn 5 beholdes:
Main.java
12345678910111213141516package com.example; import java.util.Arrays; import java.util.List; import java.util.stream.Stream; public class Main { public static void main(String[] args) { List<String> strings = Arrays.asList("Unlock", "Infinity", "with", "Codefinity"); System.out.println("List of strings: " + strings); Stream<String> stream = strings.stream(); stream = stream.filter(e -> e.length() > 5); List<String> list = stream.map(e -> e.substring(1, 4)).toList(); System.out.println("Modified list: " + list); } }
Ved å bruke filter()-metoden fjerner vi strengen "with" fra strømmen fordi dette ordet har færre enn 5 tegn.
Det er også mulig å bruke mellomliggende operasjoner flere ganger etter hverandre.
For eksempel kan vi forenkle koden ovenfor noe:
Main.java
12345678910111213141516package com.example; import java.util.Arrays; import java.util.List; public class Main { public static void main(String[] args) { List<String> strings = Arrays.asList("Unlock", "Infinity", "with", "Codefinity"); System.out.println("List of strings: " + strings); List<String> list = strings.stream() .filter(e -> e.length() > 5) .map(e -> e.substring(1, 4)) .toList(); System.out.println("Modified list: " + list); } }
Ved sammenkobling av flere strømmetoder anbefales det å plassere hver metode på en ny linje for å forbedre lesbarheten i koden betydelig.
Metoden flatMap() transformerer hvert element i en strøm til en ny strøm og kombinerer resultatene til én enkelt strøm. Med andre ord, med denne metoden kan vi dele opp strømmen i flere strømmer, som deretter slås sammen til én strøm. For eksempel, du har en liste med strenger der hver streng kan inneholde mer enn ett ord, som en liste med for- og etternavn. Og du trenger å gjøre første bokstav i hvert av disse ordene stor:
Main.java
123456789101112131415161718192021222324package com.example; import java.util.Arrays; import java.util.List; public class Main { public static void main(String[] args) { List<String> users = Arrays.asList("Ethan Johnson", "Olivia smith", "mason davis", "Ava taylor", "logan brown", "Emma Anderson", "jackson miller"); System.out.println("List of users: " + users); List<String> list = users.stream() .flatMap(e -> Arrays.stream(e.split(" "))) .map(e -> capitalizeFirstLetter(e)) .toList(); System.out.println("List with capitalized names and surnames: " + list); } private static String capitalizeFirstLetter(String word) { if (word == null || word.isEmpty()) { return word; } return Character.toUpperCase(word.charAt(0)) + word.substring(1); } }
I koden over skrev vi en egen privat metode som gjør første bokstav i et ord stor, og brukte denne metoden i map()-metoden sammen med et lambda-uttrykk.
Merk at ved å bruke flatMap-metoden deler vi opp hvert element i strømmen til ulike strømmer ved å bruke Arrays.stream(e.split(" "))-metoden. Fordi split()-metoden returnerer et array, må vi bruke Arrays.stream()-metoden for å dele opp dette arrayet i strømmer.
Deretter blir alle disse strømmene slått sammen til én strøm, og etterpå bruker vi metoden vi skrev. Nå har vi alle fornavn og etternavn til brukere med stor forbokstav.
Vet du hva som hadde vært kult?
Hvis vi legger disse fornavnene og etternavnene inn i en HashMap, hvor nøkkelen er etternavnet og verdien er fornavnet.
La oss implementere dette i koden:
Main.java
12345678910111213141516171819202122232425262728293031323334package com.example; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; public class Main { public static void main(String[] args) { List<String> users = Arrays.asList("Ethan Johnson", "Olivia smith", "mason davis", "Ava taylor", "logan brown", "Emma Anderson", "jackson miller"); System.out.println("List of users: " + users); List<String> list = users.stream() .flatMap(e -> Arrays.stream(e.split(" "))) .map(e -> capitalizeFirstLetter(e)) .toList(); System.out.println("List with capitalized names and surnames: " + list); Map<String, String> usersKeyValue = new HashMap<>(); for (int i = 0; i < list.size() - 1; i+=2) { String name = list.get(i); String surname = list.get(i + 1); usersKeyValue.put(surname, name); } System.out.println("Map with surnames as keys and names as values: " + usersKeyValue); } private static String capitalizeFirstLetter(String word) { if (word == null || word.isEmpty()) { return word; } return Character.toUpperCase(word.charAt(0)) + word.substring(1); } }
Med en enkel løkke lagret vi fornavn og etternavn i variabler og deretter i kartet. Legg merke til hvordan løkken fungerer. Vi øker variabelen i med 2 i hver iterasjon fordi vi må hoppe over etternavnet når vi allerede har registrert det.
- Metoden
distinct()fjerner duplikater fra strømmen. Generelt kan dette være nyttig hvis du trenger unike elementer i strømmen eller hvis du vil raskt eliminere duplikater fra en liste. Dette kan enkelt oppnås med følgende konstruksjon:
list.stream().distinct().toList()
-
Metoden
sortedsorterer alle elementene i strømmen i naturlig rekkefølge, fra det minste til det største tallet eller i alfabetisk rekkefølge. Dette kan også være nyttig hvis du trenger en sortert strøm eller hvis du raskt må sortere en liste; -
Metoden
skip(n)hopper over de førstenelementene i strømmen. Dette kan være nyttig når du arbeider med tekstfiler, der de første n linjene for eksempel kan være metadata eller en filbeskrivelse. Det er også verdt å nevne metodenlimit(n), som generelt begrenset antall elementer i strømmen. Selv om vi oppretter en strøm med 1000 elementer og deretter brukerlimit(200), vil strømmen kun inneholde de første 200 elementene.
Main.java
123456789101112package com.example; import java.util.Arrays; import java.util.List; public class Main { public static void main(String[] args) { List<Integer> example = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); example = example.stream().skip(3).limit(5).toList(); System.out.println("List: " + example); } }
Dette er de viktigste mellomliggende metodene du trenger å bruke. Du kan utforske resten av metodene ved å se i lenken til den offisielle Java-dokumentasjonen. La oss gå videre til terminalmetoder.
Terminalmetoder
-
Terminalmetoden du allerede kjenner til er
toList(). Den konverterer strømmen til en liste og returnerer den. Med andre ord kan du direkte tilordne denne strømmen med metoder til en liste. Denne metoden ble introdusert i Java 17 og fungerer som en erstatning for den mer komplekse konstruksjonencollect(Collectors.toList()); -
Metoden
collect()konverterer også strømmen til en spesifikk datastruktur. Den bruker, som parameter, en metode fraCollectors-grensesnittet. Dette grensesnittet har metoder somtoList(),toSet()ogtoCollection(). For eksempel:
Main.java
123456789101112131415package com.example; import java.util.Arrays; import java.util.List; import java.util.Set; import java.util.stream.Collectors; public class Main { public static void main(String[] args) { List<Integer> example = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); Set<Integer> integerSet = example.stream().collect(Collectors.toSet()); System.out.println("List: " + example); System.out.println("Set: " + integerSet); } }
Metoden forEach() tar et lambda-uttrykk og utfører en spesifikk handling for hvert element i strømmen.
For eksempel:
Main.java
1234567891011package com.example; import java.util.Arrays; import java.util.List; public class Main { public static void main(String[] args) { List<Integer> example = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); example.stream().forEach(e -> System.out.println(e + 1)); } }
Forskjellen mellom denne metoden og map-metoden er at denne metoden er terminal, og etter den kan du ikke kalle andre metoder.
Dette er alle grunnleggende metoder for arbeid med streams. Det er et komplekst emne, og du forstår det kanskje ikke med en gang. Likevel er det et tema som mestres gjennom praksis. I de kommende praksiskapitlene med streams vil du få mange muligheter til å arbeide med dem, da det er en svært praktisk og effektiv måte å håndtere lister og datastrukturer på!
1. Hva er hovedformålet med Stream API i Java?
2. Hvilken av følgende er en terminaloperasjon i Stream API?
3. Hva gjør map-operasjonen i Stream API?
4. Hvordan skiller flatMap-operasjonen seg fra map i Stream API?
5. Hva gjør filter-operasjonen i Stream API?
6. Hva er formålet med forEach-operasjonen i Stream API?
7. Hvilken av følgende er en mellomliggende operasjon i Stream API?
8. Hvordan brukes limit-operasjonen i Stream API?
Takk for tilbakemeldingene dine!