Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Lære Stream-API i Java | Avancerede Java-Funktioner og -Teknikker
Java Datastrukturer

bookStream-API i Java

Der findes forskellige måder at behandle data på i Java – løkker, metoder og forskellige algoritmer. Men i Java 8 blev et meget kraftfuldt værktøj introduceret – Stream API.

Kort sagt er Stream API en måde at arbejde hurtigt og nemt med en strøm af information. I dette tilfælde er denne informationsstrøm repræsenteret af collections. Stream API har nogle begreber. Her er de vigtigste.

Hovedbegreber

  • Stream: repræsenterer en sekvens af dataelementer, der kan behandles;

  • Mellemliggende operationer: operationer, der opretter en ny stream efter deres udførelse. Eksempler: filter, map, distinct, sorted;

  • Terminaloperationer: operationer, der afslutter behandlingen af streamen og returnerer et resultat. Eksempler: collect, forEach, count, reduce;

  • Parallelle streams: muliggør parallel behandling af data. Metoderne parallel() og parallelStream() bruges til at oprette parallelle streams.

Efter tilstrækkelig teori, lad os begynde at kode!

Deklarering af en stream udføres ved at anvende en metode på den samling, du ønsker at omdanne til en stream:

Main.java

Main.java

copy
12
List<String> strings = Arrays.asList("a", "b", "c"); Stream<String> stream = strings.stream();

Med stream()-metoden opnås en stream af strenge. For at begynde at arbejde med streamen er det dog nødvendigt at forstå, hvad lambdaudtryk er, da stream-metoder hovedsageligt anvender disse.

Lambda-udtryk

Lambda-udtryk blev introduceret i Java 8 og repræsenterer en forenklet måde at oprette anonyme funktioner i Java. Vi har ikke tidligere dækket anonyme funktioner, da de ikke har været særligt nødvendige, men nu vil vi stifte bekendtskab med dem gennem lambda-udtryk.

Lambda-udtryk syntaks:

Den generelle syntaks for lambda-udtryk i Java ser således ud:

Example.java

Example.java

copy
123
(parameters) -> expression // or (parameters) -> { statements; }
  • Parametre: dette er en parameterliste, som kan være tom eller indeholde en eller flere parametre;

  • Pil: repræsenteret ved symbolet ->, som adskiller parametrene fra kroppen af lambda-udtrykket;

  • Udtryk eller sætninger: dette er funktionens krop, som indeholder et udtryk eller et blok af sætninger.

Her er et eksempel på et lambda-udtryk, der repræsenterer en simpel funktion, som lægger to tal sammen:

Example.java

Example.java

copy
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;

Lad os se nærmere på, hvad der præcist sker i koden ovenfor, og hvordan vi anvender lambda-udtryk:

Main.java

Main.java

copy
1234567891011121314
package 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:

Oprettet et funktionelt interface MyMathOperation med en enkelt abstrakt metode operate.

Brugt et lambda-udtryk til at implementere denne metode, som udfører addition af to tal.

Udskrevet resultatet af additionen.

Det kan være udfordrende at forstå hvad der sker i denne kode på nuværende tidspunkt, men lad os vende tilbage til Stream API, hvor lambda-udtryk ofte anvendes, og forsøge at forstå, hvordan de bruges i praksis.

Som du husker, oprettede vi tidligere en stream af strenge fra en liste af strenge. Nu skal vi bruge stream-metoder til at gøre hver streng i denne stream til store bogstaver:

Main.java

Main.java

copy
12345678910111213
package 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 brugte vi et lambda-udtryk og to metoder: map() og toList(). Hvis det er tydeligt, hvad metoden toList() gør, så ændrer map()-metoden hver enkelt element i streamen i henhold til det angivne lambda-udtryk.

Lad os se nærmere på, hvordan lambda-udtrykket fungerer her:

Metoden map() anvender metoden toUpperCase() på hvert element i streamen. Vi definerede elementet i denne stream som e og instruerede programmet, ved hjælp af lambda-udtrykket, til at anvende denne metode på hvert element.

Men dette er ikke afslutningen, fordi vi har anvendt en mellemoperation. Det betyder, at operationerne på streamen ikke er afsluttet endnu. For at afslutte arbejdet med streamen skal vi anvende en terminal operation, som afslutter operationerne på streamen og returnerer en specifik værdi. For eksempel kan du bruge metoden toList(), og den ændrede stream vil blive konverteret til en liste.

For eksempel:

Main.java

Main.java

copy
1234567891011121314
package 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); } }

Lad os se nærmere på mulige mellemliggende operationer i streamen.

Mellemliggende operationer

Metoden map() – du er allerede bekendt med denne metode; den udfører de operationer, der er angivet af lambda-udtrykket, på hvert element i streamen.

For eksempel kan vi bruge metoden substring() på hvert element i en stream af strenge:

Main.java

Main.java

copy
123456789101112131415
package 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); } }

filter()-metoden anvender et lambda-udtryk med en betingelse, som strømmen filtreres ud fra. Det vil sige, at alle elementer, der opfylder betingelsen, forbliver i strømmen, mens elementer, der ikke opfylder betingelsen, fjernes fra strømmen. Strømmen ændres nu, så kun de elementer, hvis længde er større end 5, bevares:

Main.java

Main.java

copy
12345678910111213141516
package 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 brug af filter()-metoden fjerner vi strengen "with" fra strømmen, fordi dette ord har færre end 5 tegn.

Du kan også anvende mellemliggende operationer flere gange i træk.

For eksempel kan vi forenkle ovenstående kode en smule:

Main.java

Main.java

copy
12345678910111213141516
package 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); } }

Når du kæder flere stream-metoder sammen, anbefales det at placere hver metode på en ny linje for markant at forbedre læsbarheden af koden.

Metoden flatMap() transformerer hvert element i en stream til en ny stream og kombinerer resultaterne til én enkelt stream. Med andre ord kan vi med denne metode opdele streamen i flere streams, som derefter bliver flettet sammen til én stream. For eksempel har du en liste af strenge, hvor hver streng kan indeholde mere end ét ord, såsom en liste med for- og efternavne. Og du skal gøre det første bogstav stort i hvert af disse ord:

Main.java

Main.java

copy
123456789101112131415161718192021222324
package 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 ovenfor har vi skrevet en separat privat metode, der gør det første bogstav i et ord stort, og brugt denne metode i map()-metoden sammen med et lambda-udtryk.

Bemærk, at vi ved brug af flatMap-metoden opdeler hvert element i streamen til forskellige streams ved hjælp af Arrays.stream(e.split(" "))-metoden. Da split()-metoden returnerer et array, skal vi bruge Arrays.stream()-metoden for at opdele dette array i streams.

Derefter bliver alle disse streams flettet sammen til én stream, hvorefter vi bruger den metode, vi har skrevet. Nu har vi alle for- og efternavne på brugere med stort begyndelsesbogstav.

Ved du, hvad der ville være smart? Hvis vi lægger disse for- og efternavne i en HashMap, hvor nøglen er efternavnet og værdien er fornavnet.

Lad os implementere dette i koden:

Main.java

Main.java

copy
12345678910111213141516171819202122232425262728293031323334
package 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 simpel løkke blev fornavn og efternavn gemt i variabler og derefter i kortet. Bemærk, hvordan løkken fungerer. Variablen i øges med 2 i hver iteration, fordi vi skal springe efternavnet over, når det allerede er registreret.

  • Metoden distinct() fjerner dubletter fra strømmen. Generelt kan dette være nyttigt, hvis der er behov for unikke elementer i strømmen eller hvis man ønsker at hurtigt fjerne dubletter fra en liste. Dette kan nemt opnås med følgende konstruktion:
list.stream().distinct().toList()
  • Metoden sorted sorterer alle elementer i strømmen i naturlig rækkefølge, fra det mindste til det største tal eller i alfabetisk rækkefølge. Dette kan også være nyttigt, hvis der er behov for en sorteret strøm eller hvis en liste hurtigt skal sorteres;

  • Metoden skip(n) springer de første n elementer i strømmen over. Dette kan være nyttigt ved arbejde med tekstfiler, hvor de første n linjer eksempelvis kan være metadata eller en filbeskrivelse. Det er også værd at nævne metoden limit(n), som generelt begrænser antallet af elementer i strømmen. Selv hvis der oprettes en strøm med 1000 elementer og derefter bruges limit(200), vil strømmen kun indeholde de første 200 elementer.

Main.java

Main.java

copy
123456789101112
package 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 vigtigste intermediære metoder, du skal bruge. Du kan udforske resten af metoderne ved at henvise til link til den officielle Java-dokumentation. Lad os gå videre til terminalmetoder.

Terminalmetoder

  • Den terminalmetode, du allerede kender, er toList(). Den konverterer streamen til en liste og returnerer den. Med andre ord kan du direkte tildele denne stream med metoder til en liste. Denne metode blev introduceret i Java 17 og fungerer som en erstatning for den mere komplekse konstruktion collect(Collectors.toList());

  • Metoden collect() konverterer også streamen til en specifik datastruktur. Den bruger som parameter en metode fra Collectors-interfacet. Dette interface har metoder som toList(), toSet() og toCollection(). For eksempel:

Main.java

Main.java

copy
123456789101112131415
package 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() modtager et lambda-udtryk og udfører en specifik handling for hvert element i strømmen.

For eksempel:

Main.java

Main.java

copy
1234567891011
package 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)); } }

Forskellen mellem denne metode og map-metoden er, at denne metode er terminal, og efter den kan du ikke kalde andre metoder.

Dette er alle de grundlæggende metoder til at arbejde med streams. Det er et komplekst emne, og du forstår det måske ikke med det samme. Det er dog et emne, der beherskes gennem øvelse. I de kommende praksiskapitler med streams vil du få rig mulighed for at arbejde med dem, da det er en meget bekvem og praktisk måde at manipulere lister og datastrukturer på!

1. Hvad er det primære formål med Stream API i Java?

2. Hvilken af følgende er en terminal operation i Stream API?

3. Hvad gør map-operationen i Stream API'et?

4. Hvordan adskiller flatMap-operationen sig fra map i Stream API'et?

5. Hvad gør filter-operationen i Stream API'et?

6. Hvad er formålet med forEach-operationen i Stream API'et?

7. Hvilken af følgende er en intermediær operation i Stream API'et?

8. Hvordan bruges limit-operationen i Stream API'et?

question mark

Hvad er det primære formål med Stream API i Java?

Select the correct answer

question mark

Hvilken af følgende er en terminal operation i Stream API?

Select the correct answer

question mark

Hvad gør map-operationen i Stream API'et?

Select the correct answer

question mark

Hvordan adskiller flatMap-operationen sig fra map i Stream API'et?

Select the correct answer

question mark

Hvad gør filter-operationen i Stream API'et?

Select the correct answer

question mark

Hvad er formålet med forEach-operationen i Stream API'et?

Select the correct answer

question mark

Hvilken af følgende er en intermediær operation i Stream API'et?

Select the correct answer

question mark

Hvordan bruges limit-operationen i Stream API'et?

Select the correct answer

Var alt klart?

Hvordan kan vi forbedre det?

Tak for dine kommentarer!

Sektion 4. Kapitel 3

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

bookStream-API i Java

Stryg for at vise menuen

Der findes forskellige måder at behandle data på i Java – løkker, metoder og forskellige algoritmer. Men i Java 8 blev et meget kraftfuldt værktøj introduceret – Stream API.

Kort sagt er Stream API en måde at arbejde hurtigt og nemt med en strøm af information. I dette tilfælde er denne informationsstrøm repræsenteret af collections. Stream API har nogle begreber. Her er de vigtigste.

Hovedbegreber

  • Stream: repræsenterer en sekvens af dataelementer, der kan behandles;

  • Mellemliggende operationer: operationer, der opretter en ny stream efter deres udførelse. Eksempler: filter, map, distinct, sorted;

  • Terminaloperationer: operationer, der afslutter behandlingen af streamen og returnerer et resultat. Eksempler: collect, forEach, count, reduce;

  • Parallelle streams: muliggør parallel behandling af data. Metoderne parallel() og parallelStream() bruges til at oprette parallelle streams.

Efter tilstrækkelig teori, lad os begynde at kode!

Deklarering af en stream udføres ved at anvende en metode på den samling, du ønsker at omdanne til en stream:

Main.java

Main.java

copy
12
List<String> strings = Arrays.asList("a", "b", "c"); Stream<String> stream = strings.stream();

Med stream()-metoden opnås en stream af strenge. For at begynde at arbejde med streamen er det dog nødvendigt at forstå, hvad lambdaudtryk er, da stream-metoder hovedsageligt anvender disse.

Lambda-udtryk

Lambda-udtryk blev introduceret i Java 8 og repræsenterer en forenklet måde at oprette anonyme funktioner i Java. Vi har ikke tidligere dækket anonyme funktioner, da de ikke har været særligt nødvendige, men nu vil vi stifte bekendtskab med dem gennem lambda-udtryk.

Lambda-udtryk syntaks:

Den generelle syntaks for lambda-udtryk i Java ser således ud:

Example.java

Example.java

copy
123
(parameters) -> expression // or (parameters) -> { statements; }
  • Parametre: dette er en parameterliste, som kan være tom eller indeholde en eller flere parametre;

  • Pil: repræsenteret ved symbolet ->, som adskiller parametrene fra kroppen af lambda-udtrykket;

  • Udtryk eller sætninger: dette er funktionens krop, som indeholder et udtryk eller et blok af sætninger.

Her er et eksempel på et lambda-udtryk, der repræsenterer en simpel funktion, som lægger to tal sammen:

Example.java

Example.java

copy
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;

Lad os se nærmere på, hvad der præcist sker i koden ovenfor, og hvordan vi anvender lambda-udtryk:

Main.java

Main.java

copy
1234567891011121314
package 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:

Oprettet et funktionelt interface MyMathOperation med en enkelt abstrakt metode operate.

Brugt et lambda-udtryk til at implementere denne metode, som udfører addition af to tal.

Udskrevet resultatet af additionen.

Det kan være udfordrende at forstå hvad der sker i denne kode på nuværende tidspunkt, men lad os vende tilbage til Stream API, hvor lambda-udtryk ofte anvendes, og forsøge at forstå, hvordan de bruges i praksis.

Som du husker, oprettede vi tidligere en stream af strenge fra en liste af strenge. Nu skal vi bruge stream-metoder til at gøre hver streng i denne stream til store bogstaver:

Main.java

Main.java

copy
12345678910111213
package 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 brugte vi et lambda-udtryk og to metoder: map() og toList(). Hvis det er tydeligt, hvad metoden toList() gør, så ændrer map()-metoden hver enkelt element i streamen i henhold til det angivne lambda-udtryk.

Lad os se nærmere på, hvordan lambda-udtrykket fungerer her:

Metoden map() anvender metoden toUpperCase() på hvert element i streamen. Vi definerede elementet i denne stream som e og instruerede programmet, ved hjælp af lambda-udtrykket, til at anvende denne metode på hvert element.

Men dette er ikke afslutningen, fordi vi har anvendt en mellemoperation. Det betyder, at operationerne på streamen ikke er afsluttet endnu. For at afslutte arbejdet med streamen skal vi anvende en terminal operation, som afslutter operationerne på streamen og returnerer en specifik værdi. For eksempel kan du bruge metoden toList(), og den ændrede stream vil blive konverteret til en liste.

For eksempel:

Main.java

Main.java

copy
1234567891011121314
package 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); } }

Lad os se nærmere på mulige mellemliggende operationer i streamen.

Mellemliggende operationer

Metoden map() – du er allerede bekendt med denne metode; den udfører de operationer, der er angivet af lambda-udtrykket, på hvert element i streamen.

For eksempel kan vi bruge metoden substring() på hvert element i en stream af strenge:

Main.java

Main.java

copy
123456789101112131415
package 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); } }

filter()-metoden anvender et lambda-udtryk med en betingelse, som strømmen filtreres ud fra. Det vil sige, at alle elementer, der opfylder betingelsen, forbliver i strømmen, mens elementer, der ikke opfylder betingelsen, fjernes fra strømmen. Strømmen ændres nu, så kun de elementer, hvis længde er større end 5, bevares:

Main.java

Main.java

copy
12345678910111213141516
package 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 brug af filter()-metoden fjerner vi strengen "with" fra strømmen, fordi dette ord har færre end 5 tegn.

Du kan også anvende mellemliggende operationer flere gange i træk.

For eksempel kan vi forenkle ovenstående kode en smule:

Main.java

Main.java

copy
12345678910111213141516
package 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); } }

Når du kæder flere stream-metoder sammen, anbefales det at placere hver metode på en ny linje for markant at forbedre læsbarheden af koden.

Metoden flatMap() transformerer hvert element i en stream til en ny stream og kombinerer resultaterne til én enkelt stream. Med andre ord kan vi med denne metode opdele streamen i flere streams, som derefter bliver flettet sammen til én stream. For eksempel har du en liste af strenge, hvor hver streng kan indeholde mere end ét ord, såsom en liste med for- og efternavne. Og du skal gøre det første bogstav stort i hvert af disse ord:

Main.java

Main.java

copy
123456789101112131415161718192021222324
package 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 ovenfor har vi skrevet en separat privat metode, der gør det første bogstav i et ord stort, og brugt denne metode i map()-metoden sammen med et lambda-udtryk.

Bemærk, at vi ved brug af flatMap-metoden opdeler hvert element i streamen til forskellige streams ved hjælp af Arrays.stream(e.split(" "))-metoden. Da split()-metoden returnerer et array, skal vi bruge Arrays.stream()-metoden for at opdele dette array i streams.

Derefter bliver alle disse streams flettet sammen til én stream, hvorefter vi bruger den metode, vi har skrevet. Nu har vi alle for- og efternavne på brugere med stort begyndelsesbogstav.

Ved du, hvad der ville være smart? Hvis vi lægger disse for- og efternavne i en HashMap, hvor nøglen er efternavnet og værdien er fornavnet.

Lad os implementere dette i koden:

Main.java

Main.java

copy
12345678910111213141516171819202122232425262728293031323334
package 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 simpel løkke blev fornavn og efternavn gemt i variabler og derefter i kortet. Bemærk, hvordan løkken fungerer. Variablen i øges med 2 i hver iteration, fordi vi skal springe efternavnet over, når det allerede er registreret.

  • Metoden distinct() fjerner dubletter fra strømmen. Generelt kan dette være nyttigt, hvis der er behov for unikke elementer i strømmen eller hvis man ønsker at hurtigt fjerne dubletter fra en liste. Dette kan nemt opnås med følgende konstruktion:
list.stream().distinct().toList()
  • Metoden sorted sorterer alle elementer i strømmen i naturlig rækkefølge, fra det mindste til det største tal eller i alfabetisk rækkefølge. Dette kan også være nyttigt, hvis der er behov for en sorteret strøm eller hvis en liste hurtigt skal sorteres;

  • Metoden skip(n) springer de første n elementer i strømmen over. Dette kan være nyttigt ved arbejde med tekstfiler, hvor de første n linjer eksempelvis kan være metadata eller en filbeskrivelse. Det er også værd at nævne metoden limit(n), som generelt begrænser antallet af elementer i strømmen. Selv hvis der oprettes en strøm med 1000 elementer og derefter bruges limit(200), vil strømmen kun indeholde de første 200 elementer.

Main.java

Main.java

copy
123456789101112
package 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 vigtigste intermediære metoder, du skal bruge. Du kan udforske resten af metoderne ved at henvise til link til den officielle Java-dokumentation. Lad os gå videre til terminalmetoder.

Terminalmetoder

  • Den terminalmetode, du allerede kender, er toList(). Den konverterer streamen til en liste og returnerer den. Med andre ord kan du direkte tildele denne stream med metoder til en liste. Denne metode blev introduceret i Java 17 og fungerer som en erstatning for den mere komplekse konstruktion collect(Collectors.toList());

  • Metoden collect() konverterer også streamen til en specifik datastruktur. Den bruger som parameter en metode fra Collectors-interfacet. Dette interface har metoder som toList(), toSet() og toCollection(). For eksempel:

Main.java

Main.java

copy
123456789101112131415
package 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() modtager et lambda-udtryk og udfører en specifik handling for hvert element i strømmen.

For eksempel:

Main.java

Main.java

copy
1234567891011
package 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)); } }

Forskellen mellem denne metode og map-metoden er, at denne metode er terminal, og efter den kan du ikke kalde andre metoder.

Dette er alle de grundlæggende metoder til at arbejde med streams. Det er et komplekst emne, og du forstår det måske ikke med det samme. Det er dog et emne, der beherskes gennem øvelse. I de kommende praksiskapitler med streams vil du få rig mulighed for at arbejde med dem, da det er en meget bekvem og praktisk måde at manipulere lister og datastrukturer på!

1. Hvad er det primære formål med Stream API i Java?

2. Hvilken af følgende er en terminal operation i Stream API?

3. Hvad gør map-operationen i Stream API'et?

4. Hvordan adskiller flatMap-operationen sig fra map i Stream API'et?

5. Hvad gør filter-operationen i Stream API'et?

6. Hvad er formålet med forEach-operationen i Stream API'et?

7. Hvilken af følgende er en intermediær operation i Stream API'et?

8. Hvordan bruges limit-operationen i Stream API'et?

question mark

Hvad er det primære formål med Stream API i Java?

Select the correct answer

question mark

Hvilken af følgende er en terminal operation i Stream API?

Select the correct answer

question mark

Hvad gør map-operationen i Stream API'et?

Select the correct answer

question mark

Hvordan adskiller flatMap-operationen sig fra map i Stream API'et?

Select the correct answer

question mark

Hvad gør filter-operationen i Stream API'et?

Select the correct answer

question mark

Hvad er formålet med forEach-operationen i Stream API'et?

Select the correct answer

question mark

Hvilken af følgende er en intermediær operation i Stream API'et?

Select the correct answer

question mark

Hvordan bruges limit-operationen i Stream API'et?

Select the correct answer

Var alt klart?

Hvordan kan vi forbedre det?

Tak for dine kommentarer!

Sektion 4. Kapitel 3
some-alt