Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Lernen Stream-API in Java | Erweiterte Java-Funktionen und -Techniken
Java Datenstrukturen

bookStream-API in Java

Es gibt verschiedene Möglichkeiten, Daten in Java zu verarbeiten – Schleifen, Methoden und unterschiedliche Algorithmen. Mit Java 8 wurde jedoch ein sehr leistungsfähiges Werkzeug eingeführt – die Stream-API.

Einfach ausgedrückt ist die Stream-API eine Möglichkeit, schnell und unkompliziert mit einem Informationsstrom zu arbeiten. In unserem Fall wird dieser Informationsstrom durch Collections dargestellt. Die Stream-API umfasst einige Konzepte. Hier sind die wichtigsten.

Hauptkonzepte

  • Stream: Repräsentiert eine Sequenz von Datenelementen, die verarbeitet werden können;

  • Intermediate Operations: Operationen, die nach ihrer Ausführung einen neuen Stream erzeugen. Beispiele: filter, map, distinct, sorted;

  • Terminal Operations: Operationen, die die Verarbeitung des Streams abschließen und ein Ergebnis zurückgeben. Beispiele: collect, forEach, count, reduce;

  • Parallele Streams: Ermöglichen die parallele Verarbeitung von Daten. Die Methoden parallel() und parallelStream() werden verwendet, um parallele Streams zu erzeugen.

Genug Theorie, beginnen wir mit dem Programmieren!

Die Deklaration eines Streams erfolgt durch die Verwendung einer Methode auf der Sammlung, die in einen Stream umgewandelt werden soll:

Main.java

Main.java

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

Mit der Methode stream() wurde ein Stream von Strings erzeugt. Um jedoch mit dem Stream zu arbeiten, ist es notwendig, Lambda-Ausdrücke zu verstehen, da die Methoden von Streams hauptsächlich mit diesen arbeiten.

Lambda-Ausdrücke

Lambda-Ausdrücke wurden in Java 8 eingeführt und stellen eine vereinfachte Form zur Erstellung anonymer Funktionen in Java dar. Anonyme Funktionen wurden bisher nicht behandelt, da sie bislang nicht zwingend erforderlich waren. Nun werden wir sie anhand von Lambda-Ausdrücken kennenlernen.

Syntax von Lambda-Ausdrücken:

Die allgemeine Syntax für Lambda-Ausdrücke in Java sieht folgendermaßen aus:

Example.java

Example.java

copy
123
(parameters) -> expression // or (parameters) -> { statements; }
  • Parameter: Dies ist eine Parameterliste, die leer sein oder einen oder mehrere Parameter enthalten kann;

  • Pfeil: Dargestellt durch das Symbol ->, das die Parameter vom Rumpf des Lambda-Ausdrucks trennt;

  • Ausdruck oder Anweisungen: Dies ist der Funktionsrumpf, der einen Ausdruck oder einen Block von Anweisungen enthält.

Hier ist ein Beispiel für einen Lambda-Ausdruck, der eine einfache Funktion darstellt, die zwei Zahlen addiert:

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;

Werfen wir einen genaueren Blick darauf, was im obigen Code genau passiert und wie Lambda-Ausdrücke verwendet werden:

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)); } }

Im obigen Code:

Eine funktionale Schnittstelle MyMathOperation mit einer einzigen abstrakten Methode operate wurde erstellt.

Eine Lambda-Ausdruck wurde verwendet, um diese Methode zu implementieren, wobei die Addition von zwei Zahlen durchgeführt wird.

Das Ergebnis der Addition wurde ausgegeben.

Es ist verständlich, dass es schwierig nachzuvollziehen sein kann, was in diesem Code aktuell passiert. Kehren wir jedoch zurück zur Stream-API, bei der Lambda-Ausdrücke häufig verwendet werden, und versuchen wir zu verstehen, wie man sie in der Praxis einsetzt.

Wie Sie sich erinnern, haben wir zuvor einen Stream von Strings aus einer Liste von Strings erstellt. Nun verwenden wir Stream-Methoden, um jeden String in diesem Stream in Großbuchstaben umzuwandeln:

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(); } }

Im obigen Code wurde ein Lambda-Ausdruck sowie zwei Methoden verwendet: map() und toList(). Während die Funktion der Methode toList() offensichtlich ist, verändert die Methode map() jedes Element im Stream entsprechend dem übergebenen Lambda-Ausdruck.

Im Folgenden wird näher betrachtet, wie der Lambda-Ausdruck hier funktioniert:

Die Methode map() wendet die Methode toUpperCase() auf jedes Element des Streams an. Das Element dieses Streams wurde als e definiert und mit dem Lambda-Ausdruck wurde das Programm angewiesen, diese Methode auf jedes Element anzuwenden.

Dies ist jedoch noch nicht das Ende, da eine intermediäre Operation angewendet wurde. Das bedeutet, dass Operationen auf dem Stream noch nicht abgeschlossen sind. Um die Arbeit am Stream abzuschließen, muss eine terminale Operation angewendet werden, die die Operationen am Stream beendet und einen bestimmten Wert zurückgibt. Beispielsweise kann die Methode toList() verwendet werden, wodurch der modifizierte Stream in eine Liste umgewandelt wird.

Zum Beispiel:

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); } }

Werfen wir einen genaueren Blick auf mögliche Zwischenoperationen im Stream.

Zwischenoperationen

Die Methode map() – diese Methode ist bereits bekannt; sie führt die durch den Lambda-Ausdruck spezifizierten Operationen auf jedem Element im Stream aus.

Beispielsweise kann die Methode substring() auf jedes Element eines String-Streams angewendet werden:

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); } }

Die Methode filter() verwendet einen Lambda-Ausdruck mit einer Bedingung, anhand derer der Stream gefiltert wird. Das bedeutet, alle Elemente, die die Bedingung erfüllen, verbleiben im Stream, während Elemente, die die Bedingung nicht erfüllen, aus dem Stream entfernt werden. Der Stream wird so angepasst, dass nur noch die Elemente erhalten bleiben, deren Länge größer als 5 ist:

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); } }

Mit der Methode filter() entfernen wir den String "with" aus dem Stream, da dieses Wort weniger als 5 Zeichen hat.

Mehrfache Zwischenoperationen können auch hintereinander verwendet werden.

Zum Beispiel lässt sich der obige Code etwas vereinfachen:

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); } }

Beim Verketten von mehreren Stream-Methoden wird empfohlen, jede Methode in eine neue Zeile zu schreiben, um die Lesbarkeit des Codes deutlich zu verbessern.

Die Methode flatMap() wandelt jedes Element eines Streams in einen neuen Stream um und kombiniert die Ergebnisse zu einem einzigen Stream. Mit dieser Methode kann der Stream also in mehrere Streams aufgeteilt und anschließend zu einem Stream zusammengeführt werden. Zum Beispiel gibt es eine Liste von Zeichenketten, bei denen jede Zeichenkette mehr als ein Wort enthalten kann, wie etwa eine Liste von Vor- und Nachnamen. Und es ist erforderlich, den ersten Buchstaben jedes dieser Wörter zu kapitalisieren:

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); } }

Im obigen Code wurde eine separate private Methode geschrieben, die den ersten Buchstaben eines Wortes kapitalisiert, und diese Methode wurde zusammen mit einem Lambda-Ausdruck in der Methode map() verwendet.

Beachte, dass mit der Methode flatMap jedes Element des Streams mithilfe von Arrays.stream(e.split(" ")) in verschiedene Streams aufgeteilt wird. Da die Methode split() ein Array zurückgibt, muss die Methode Arrays.stream() verwendet werden, um dieses Array in Streams zu teilen.

Anschließend werden alle diese Streams zu einem Stream zusammengeführt, woraufhin die geschriebene Methode verwendet wird. Nun liegen alle Vor- und Nachnamen der Benutzer mit großgeschriebenem Anfangsbuchstaben vor.

Wissen Sie, was interessant wäre? Wenn diese Vor- und Nachnamen in eine HashMap eingefügt werden, wobei der Schlüssel der Nachname und der Wert der Vorname ist.

Lassen Sie uns dies im Code umsetzen:

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); } }

Mit einer einfachen Schleife wurden der Vorname und Nachname in Variablen gespeichert und anschließend in die Map eingefügt. Beachten Sie, wie die Schleife funktioniert. Die Variable i wird in jeder Iteration um 2 erhöht, da der Nachname übersprungen werden muss, sobald er bereits erfasst wurde.

  • Die Methode distinct() entfernt Duplikate aus dem Stream. Dies ist im Allgemeinen nützlich, wenn eindeutige Elemente im Stream benötigt werden oder wenn Duplikate aus einer Liste schnell entfernt werden sollen. Dies kann einfach mit folgender Konstruktion erreicht werden:
list.stream().distinct().toList()
  • Die Methode sorted sortiert alle Elemente im Stream in natürlicher Reihenfolge, also von der kleinsten zur größten Zahl oder alphabetisch. Dies ist ebenfalls nützlich, wenn ein sortierter Stream benötigt wird oder eine Liste schnell sortiert werden soll;

  • Die Methode skip(n) überspringt die ersten n Elemente des Streams. Dies ist hilfreich beim Arbeiten mit Textdateien, bei denen die ersten n Zeilen beispielsweise Metadaten oder eine Dateibeschreibung enthalten können. Erwähnenswert ist auch die Methode limit(n), die die Anzahl der Elemente im Stream begrenzt. Selbst wenn ein Stream mit 1000 Elementen erstellt wird und anschließend limit(200) verwendet wird, enthält der Stream nur die ersten 200 Elemente.

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); } }

Dies sind die wichtigsten intermediären Methoden, die benötigt werden. Weitere Methoden können in der Link zur offiziellen Java-Dokumentation nachgelesen werden. Im Folgenden werden die Terminalmethoden behandelt.

Terminalmethoden

  • Die bereits bekannte Terminalmethode ist toList(). Sie wandelt den Stream in eine Liste um und gibt diese zurück. Das bedeutet, dass dieser Stream mit Methoden direkt einer Liste zugewiesen werden kann. Diese Methode wurde in Java 17 eingeführt und ersetzt die komplexere Konstruktion collect(Collectors.toList());

  • Die Methode collect() wandelt den Stream ebenfalls in eine bestimmte Datenstruktur um. Sie verwendet als Parameter eine Methode aus dem Interface Collectors. Dieses Interface enthält Methoden wie toList(), toSet() und toCollection(). Zum Beispiel:

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); } }

Die Methode forEach() nimmt einen Lambda-Ausdruck entgegen und führt für jedes Element im Stream eine bestimmte Aktion aus.

Zum Beispiel:

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)); } }

Der Unterschied zwischen dieser Methode und der map-Methode besteht darin, dass diese Methode terminal ist und danach keine weiteren Methoden aufgerufen werden können.

Dies sind alle grundlegenden Methoden zur Arbeit mit Streams. Es handelt sich um ein komplexes Thema, das nicht sofort verstanden werden muss. Allerdings ist es ein Thema, das durch Übung beherrscht wird. In den folgenden Übungskapiteln zu Streams werden Sie zahlreiche Möglichkeiten haben, damit zu arbeiten, da es eine sehr bequeme und praktische Methode zur Verarbeitung von Listen und Datenarrays ist!

1. Was ist der Hauptzweck der Stream-API in Java?

2. Welche der folgenden ist eine terminale Operation in der Stream-API?

3. Was bewirkt die map-Operation in der Stream-API?

4. Worin unterscheidet sich die flatMap-Operation von map in der Stream-API?

5. Was bewirkt die filter-Operation in der Stream-API?

6. Was ist der Zweck der forEach-Operation in der Stream-API?

7. Welche der folgenden ist eine Zwischenoperation in der Stream-API?

8. Wie wird die limit-Operation in der Stream-API verwendet?

question mark

Was ist der Hauptzweck der Stream-API in Java?

Select the correct answer

question mark

Welche der folgenden ist eine terminale Operation in der Stream-API?

Select the correct answer

question mark

Was bewirkt die map-Operation in der Stream-API?

Select the correct answer

question mark

Worin unterscheidet sich die flatMap-Operation von map in der Stream-API?

Select the correct answer

question mark

Was bewirkt die filter-Operation in der Stream-API?

Select the correct answer

question mark

Was ist der Zweck der forEach-Operation in der Stream-API?

Select the correct answer

question mark

Welche der folgenden ist eine Zwischenoperation in der Stream-API?

Select the correct answer

question mark

Wie wird die limit-Operation in der Stream-API verwendet?

Select the correct answer

War alles klar?

Wie können wir es verbessern?

Danke für Ihr Feedback!

Abschnitt 4. Kapitel 3

Fragen Sie AI

expand

Fragen Sie AI

ChatGPT

Fragen Sie alles oder probieren Sie eine der vorgeschlagenen Fragen, um unser Gespräch zu beginnen

Suggested prompts:

Can you explain more about how lambda expressions work with streams?

What are some common use cases for the Stream API in real-world Java projects?

Could you provide more examples of intermediate and terminal operations?

bookStream-API in Java

Swipe um das Menü anzuzeigen

Es gibt verschiedene Möglichkeiten, Daten in Java zu verarbeiten – Schleifen, Methoden und unterschiedliche Algorithmen. Mit Java 8 wurde jedoch ein sehr leistungsfähiges Werkzeug eingeführt – die Stream-API.

Einfach ausgedrückt ist die Stream-API eine Möglichkeit, schnell und unkompliziert mit einem Informationsstrom zu arbeiten. In unserem Fall wird dieser Informationsstrom durch Collections dargestellt. Die Stream-API umfasst einige Konzepte. Hier sind die wichtigsten.

Hauptkonzepte

  • Stream: Repräsentiert eine Sequenz von Datenelementen, die verarbeitet werden können;

  • Intermediate Operations: Operationen, die nach ihrer Ausführung einen neuen Stream erzeugen. Beispiele: filter, map, distinct, sorted;

  • Terminal Operations: Operationen, die die Verarbeitung des Streams abschließen und ein Ergebnis zurückgeben. Beispiele: collect, forEach, count, reduce;

  • Parallele Streams: Ermöglichen die parallele Verarbeitung von Daten. Die Methoden parallel() und parallelStream() werden verwendet, um parallele Streams zu erzeugen.

Genug Theorie, beginnen wir mit dem Programmieren!

Die Deklaration eines Streams erfolgt durch die Verwendung einer Methode auf der Sammlung, die in einen Stream umgewandelt werden soll:

Main.java

Main.java

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

Mit der Methode stream() wurde ein Stream von Strings erzeugt. Um jedoch mit dem Stream zu arbeiten, ist es notwendig, Lambda-Ausdrücke zu verstehen, da die Methoden von Streams hauptsächlich mit diesen arbeiten.

Lambda-Ausdrücke

Lambda-Ausdrücke wurden in Java 8 eingeführt und stellen eine vereinfachte Form zur Erstellung anonymer Funktionen in Java dar. Anonyme Funktionen wurden bisher nicht behandelt, da sie bislang nicht zwingend erforderlich waren. Nun werden wir sie anhand von Lambda-Ausdrücken kennenlernen.

Syntax von Lambda-Ausdrücken:

Die allgemeine Syntax für Lambda-Ausdrücke in Java sieht folgendermaßen aus:

Example.java

Example.java

copy
123
(parameters) -> expression // or (parameters) -> { statements; }
  • Parameter: Dies ist eine Parameterliste, die leer sein oder einen oder mehrere Parameter enthalten kann;

  • Pfeil: Dargestellt durch das Symbol ->, das die Parameter vom Rumpf des Lambda-Ausdrucks trennt;

  • Ausdruck oder Anweisungen: Dies ist der Funktionsrumpf, der einen Ausdruck oder einen Block von Anweisungen enthält.

Hier ist ein Beispiel für einen Lambda-Ausdruck, der eine einfache Funktion darstellt, die zwei Zahlen addiert:

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;

Werfen wir einen genaueren Blick darauf, was im obigen Code genau passiert und wie Lambda-Ausdrücke verwendet werden:

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)); } }

Im obigen Code:

Eine funktionale Schnittstelle MyMathOperation mit einer einzigen abstrakten Methode operate wurde erstellt.

Eine Lambda-Ausdruck wurde verwendet, um diese Methode zu implementieren, wobei die Addition von zwei Zahlen durchgeführt wird.

Das Ergebnis der Addition wurde ausgegeben.

Es ist verständlich, dass es schwierig nachzuvollziehen sein kann, was in diesem Code aktuell passiert. Kehren wir jedoch zurück zur Stream-API, bei der Lambda-Ausdrücke häufig verwendet werden, und versuchen wir zu verstehen, wie man sie in der Praxis einsetzt.

Wie Sie sich erinnern, haben wir zuvor einen Stream von Strings aus einer Liste von Strings erstellt. Nun verwenden wir Stream-Methoden, um jeden String in diesem Stream in Großbuchstaben umzuwandeln:

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(); } }

Im obigen Code wurde ein Lambda-Ausdruck sowie zwei Methoden verwendet: map() und toList(). Während die Funktion der Methode toList() offensichtlich ist, verändert die Methode map() jedes Element im Stream entsprechend dem übergebenen Lambda-Ausdruck.

Im Folgenden wird näher betrachtet, wie der Lambda-Ausdruck hier funktioniert:

Die Methode map() wendet die Methode toUpperCase() auf jedes Element des Streams an. Das Element dieses Streams wurde als e definiert und mit dem Lambda-Ausdruck wurde das Programm angewiesen, diese Methode auf jedes Element anzuwenden.

Dies ist jedoch noch nicht das Ende, da eine intermediäre Operation angewendet wurde. Das bedeutet, dass Operationen auf dem Stream noch nicht abgeschlossen sind. Um die Arbeit am Stream abzuschließen, muss eine terminale Operation angewendet werden, die die Operationen am Stream beendet und einen bestimmten Wert zurückgibt. Beispielsweise kann die Methode toList() verwendet werden, wodurch der modifizierte Stream in eine Liste umgewandelt wird.

Zum Beispiel:

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); } }

Werfen wir einen genaueren Blick auf mögliche Zwischenoperationen im Stream.

Zwischenoperationen

Die Methode map() – diese Methode ist bereits bekannt; sie führt die durch den Lambda-Ausdruck spezifizierten Operationen auf jedem Element im Stream aus.

Beispielsweise kann die Methode substring() auf jedes Element eines String-Streams angewendet werden:

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); } }

Die Methode filter() verwendet einen Lambda-Ausdruck mit einer Bedingung, anhand derer der Stream gefiltert wird. Das bedeutet, alle Elemente, die die Bedingung erfüllen, verbleiben im Stream, während Elemente, die die Bedingung nicht erfüllen, aus dem Stream entfernt werden. Der Stream wird so angepasst, dass nur noch die Elemente erhalten bleiben, deren Länge größer als 5 ist:

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); } }

Mit der Methode filter() entfernen wir den String "with" aus dem Stream, da dieses Wort weniger als 5 Zeichen hat.

Mehrfache Zwischenoperationen können auch hintereinander verwendet werden.

Zum Beispiel lässt sich der obige Code etwas vereinfachen:

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); } }

Beim Verketten von mehreren Stream-Methoden wird empfohlen, jede Methode in eine neue Zeile zu schreiben, um die Lesbarkeit des Codes deutlich zu verbessern.

Die Methode flatMap() wandelt jedes Element eines Streams in einen neuen Stream um und kombiniert die Ergebnisse zu einem einzigen Stream. Mit dieser Methode kann der Stream also in mehrere Streams aufgeteilt und anschließend zu einem Stream zusammengeführt werden. Zum Beispiel gibt es eine Liste von Zeichenketten, bei denen jede Zeichenkette mehr als ein Wort enthalten kann, wie etwa eine Liste von Vor- und Nachnamen. Und es ist erforderlich, den ersten Buchstaben jedes dieser Wörter zu kapitalisieren:

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); } }

Im obigen Code wurde eine separate private Methode geschrieben, die den ersten Buchstaben eines Wortes kapitalisiert, und diese Methode wurde zusammen mit einem Lambda-Ausdruck in der Methode map() verwendet.

Beachte, dass mit der Methode flatMap jedes Element des Streams mithilfe von Arrays.stream(e.split(" ")) in verschiedene Streams aufgeteilt wird. Da die Methode split() ein Array zurückgibt, muss die Methode Arrays.stream() verwendet werden, um dieses Array in Streams zu teilen.

Anschließend werden alle diese Streams zu einem Stream zusammengeführt, woraufhin die geschriebene Methode verwendet wird. Nun liegen alle Vor- und Nachnamen der Benutzer mit großgeschriebenem Anfangsbuchstaben vor.

Wissen Sie, was interessant wäre? Wenn diese Vor- und Nachnamen in eine HashMap eingefügt werden, wobei der Schlüssel der Nachname und der Wert der Vorname ist.

Lassen Sie uns dies im Code umsetzen:

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); } }

Mit einer einfachen Schleife wurden der Vorname und Nachname in Variablen gespeichert und anschließend in die Map eingefügt. Beachten Sie, wie die Schleife funktioniert. Die Variable i wird in jeder Iteration um 2 erhöht, da der Nachname übersprungen werden muss, sobald er bereits erfasst wurde.

  • Die Methode distinct() entfernt Duplikate aus dem Stream. Dies ist im Allgemeinen nützlich, wenn eindeutige Elemente im Stream benötigt werden oder wenn Duplikate aus einer Liste schnell entfernt werden sollen. Dies kann einfach mit folgender Konstruktion erreicht werden:
list.stream().distinct().toList()
  • Die Methode sorted sortiert alle Elemente im Stream in natürlicher Reihenfolge, also von der kleinsten zur größten Zahl oder alphabetisch. Dies ist ebenfalls nützlich, wenn ein sortierter Stream benötigt wird oder eine Liste schnell sortiert werden soll;

  • Die Methode skip(n) überspringt die ersten n Elemente des Streams. Dies ist hilfreich beim Arbeiten mit Textdateien, bei denen die ersten n Zeilen beispielsweise Metadaten oder eine Dateibeschreibung enthalten können. Erwähnenswert ist auch die Methode limit(n), die die Anzahl der Elemente im Stream begrenzt. Selbst wenn ein Stream mit 1000 Elementen erstellt wird und anschließend limit(200) verwendet wird, enthält der Stream nur die ersten 200 Elemente.

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); } }

Dies sind die wichtigsten intermediären Methoden, die benötigt werden. Weitere Methoden können in der Link zur offiziellen Java-Dokumentation nachgelesen werden. Im Folgenden werden die Terminalmethoden behandelt.

Terminalmethoden

  • Die bereits bekannte Terminalmethode ist toList(). Sie wandelt den Stream in eine Liste um und gibt diese zurück. Das bedeutet, dass dieser Stream mit Methoden direkt einer Liste zugewiesen werden kann. Diese Methode wurde in Java 17 eingeführt und ersetzt die komplexere Konstruktion collect(Collectors.toList());

  • Die Methode collect() wandelt den Stream ebenfalls in eine bestimmte Datenstruktur um. Sie verwendet als Parameter eine Methode aus dem Interface Collectors. Dieses Interface enthält Methoden wie toList(), toSet() und toCollection(). Zum Beispiel:

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); } }

Die Methode forEach() nimmt einen Lambda-Ausdruck entgegen und führt für jedes Element im Stream eine bestimmte Aktion aus.

Zum Beispiel:

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)); } }

Der Unterschied zwischen dieser Methode und der map-Methode besteht darin, dass diese Methode terminal ist und danach keine weiteren Methoden aufgerufen werden können.

Dies sind alle grundlegenden Methoden zur Arbeit mit Streams. Es handelt sich um ein komplexes Thema, das nicht sofort verstanden werden muss. Allerdings ist es ein Thema, das durch Übung beherrscht wird. In den folgenden Übungskapiteln zu Streams werden Sie zahlreiche Möglichkeiten haben, damit zu arbeiten, da es eine sehr bequeme und praktische Methode zur Verarbeitung von Listen und Datenarrays ist!

1. Was ist der Hauptzweck der Stream-API in Java?

2. Welche der folgenden ist eine terminale Operation in der Stream-API?

3. Was bewirkt die map-Operation in der Stream-API?

4. Worin unterscheidet sich die flatMap-Operation von map in der Stream-API?

5. Was bewirkt die filter-Operation in der Stream-API?

6. Was ist der Zweck der forEach-Operation in der Stream-API?

7. Welche der folgenden ist eine Zwischenoperation in der Stream-API?

8. Wie wird die limit-Operation in der Stream-API verwendet?

question mark

Was ist der Hauptzweck der Stream-API in Java?

Select the correct answer

question mark

Welche der folgenden ist eine terminale Operation in der Stream-API?

Select the correct answer

question mark

Was bewirkt die map-Operation in der Stream-API?

Select the correct answer

question mark

Worin unterscheidet sich die flatMap-Operation von map in der Stream-API?

Select the correct answer

question mark

Was bewirkt die filter-Operation in der Stream-API?

Select the correct answer

question mark

Was ist der Zweck der forEach-Operation in der Stream-API?

Select the correct answer

question mark

Welche der folgenden ist eine Zwischenoperation in der Stream-API?

Select the correct answer

question mark

Wie wird die limit-Operation in der Stream-API verwendet?

Select the correct answer

War alles klar?

Wie können wir es verbessern?

Danke für Ihr Feedback!

Abschnitt 4. Kapitel 3
some-alt