Prinzipien
Die Prinzipien der Arbeit mit der Stream-API basieren auf den zentralen Konzepten der funktionalen Programmierung und der Lazy Evaluation. Im Folgenden werden die wichtigsten Prinzipien der Stream-API vorgestellt.
Lazy Evaluation
Eines der grundlegenden Prinzipien der Stream-API ist die Lazy Evaluation.
Das bedeutet, dass intermediäre Operationen wie filter() oder map() nicht sofort ausgeführt werden. Sie bilden lediglich eine Kette von Aktionen, die erst dann ausgeführt wird, wenn eine abschließende Operation wie collect() oder forEach() aufgerufen wird.
Main.java
12345678910111213package com.example; import java.util.List; public class Main { public static void main(String[] args) { List<String> names = List.of("Alice", "Bob", "Charlie"); long count = names.stream() .filter(name -> name.startsWith("A")) // Forming the operation .count(); // Triggering execution System.out.println(count); // Output: 1 } }
Dieser Code erstellt einen Stream aus einer Liste von Strings, filtert die Elemente, sodass nur diejenigen erhalten bleiben, die mit dem Buchstaben A beginnen, und zählt, wie viele die Bedingung erfüllen. Das Ergebnis (1) wird ausgegeben, da nur Alice die Bedingung erfüllt.
Funktionaler Programmierstil
Die Stream API verwendet Lambda-Ausdrücke und funktionale Schnittstellen zur Datenverarbeitung. Anstelle des imperativen Ansatzes mit Schleifen wird beschrieben, was mit den Daten geschehen soll:
Main.java
1234567891011121314package com.example; import java.util.List; public class Main { public static void main(String[] args) { List<String> fruits = List.of("apple", "banana", "cherry", "apricot", "blueberry"); List<String> result = fruits.stream() .map(String::toUpperCase) // Convert all strings to uppercase .skip(3) .toList(); // Collect the result into a new list System.out.println(result); } }
Dieser Code erstellt einen Stream aus einer Liste von Früchten, wandelt die Strings mit map() in Großbuchstaben um und überspringt mit skip() die ersten drei Elemente. Das Ergebnis wird in eine neue Liste gesammelt und ausgegeben, beginnend ab dem vierten Element.
Unveränderlichkeit der Daten
Die Stream API verändert die Originaldaten nicht. Alle Operationen erzeugen einen neuen Stream oder liefern ein Ergebnis zurück, ohne die Sammlung oder das Array zu verändern. Dies erhöht die Datensicherheit und verhindert unerwartete Nebeneffekte.
Main.java
12345678910111213package com.example; import java.util.List; public class Main { public static void main(String[] args) { List<String> names = List.of("Alice", "Bob", "Charlie"); List<String> updateNames = names.stream() .filter(name -> name.startsWith("A")) .toList(); System.out.println(names); // Output: [Alice, Bob, Charlie] } }
Die Stream-API filtert die Listennamen, um einen neuen Stream updateNames zu erstellen, der nur Elemente enthält, die mit dem Buchstaben A beginnen. Die ursprüngliche Liste names bleibt jedoch unverändert, da die Stream-API die Daten nicht direkt verändert. Dies gewährleistet Datensicherheit und verhindert Nebenwirkungen.
Streams sind nur einmal konsumierbar
Ein Stream kann nur einmal verwendet werden. Nach Ausführung einer terminalen Operation steht der Stream für weitere Verarbeitung nicht mehr zur Verfügung.
Main.java
123456789101112package com.example; import java.util.List; import java.util.stream.Stream; public class Main { public static void main(String[] args) { Stream<String> stream = List.of("Alice", "Bob").stream(); stream.forEach(System.out::println); stream.forEach(System.out::println); // Error: Stream has already been used } }
Hier wird ein Stream aus einer Liste von Strings erstellt und jedes Element auf die Konsole ausgegeben. Nachdem der Stream einmal verwendet wurde, kann er nicht wiederverwendet werden, was zu einem Fehler führt, wenn versucht wird, forEach() erneut aufzurufen.
Parallele Verarbeitung
Die Stream-API unterstützt parallele Streams und ermöglicht dadurch eine schnellere Datenverarbeitung auf Mehrkernsystemen. Dies wird ausführlicher hier behandelt.
Main.java
1234567891011package com.example; import java.util.List; public class Main { public static void main(String[] args) { List<Integer> numbers = List.of(1, 2, 3, 4, 5); numbers.parallelStream() .forEach(System.out::println); // Elements are processed in parallel } }
Dieser Code erstellt einen parallelen Stream aus einer Liste von Zahlen und gibt jedes Element auf der Konsole aus. Die Verwendung von parallelStream() ermöglicht eine parallele Verarbeitung der Listenelemente, was die Ausführung beschleunigen kann, insbesondere bei großen Datenmengen.
Code-Sauberkeit und Lesbarkeit
Die Verwendung der Stream API macht den Code deklarativer. Anstatt zu beschreiben, wie eine Aufgabe ausgeführt werden soll (wie bei der Verwendung von Schleifen), wird beschrieben, was genau erledigt werden muss. Dies verbessert die Lesbarkeit und vereinfacht die Wartung des Codes.
Beispiel mit einer Schleife:
List<String> names = List.of("Alice", "Bob", "Charlie");
for (String name : names) {
System.out.println(name);
}
Beispiel mit der Stream-API:
List<String> names = List.of("Alice", "Bob", "Charlie");
names.stream().forEach(System.out::println);
Im ersten Schleifenbeispiel wird explizit beschrieben, wie durch die Liste iteriert und die Elemente ausgegeben werden, während im zweiten Beispiel mit der Stream-API lediglich angegeben wird, was gemacht werden soll: Durchlaufen der Elemente und deren Ausgabe. Dadurch wird der Code deklarativer und lesbarer.
Danke für Ihr Feedback!
Fragen Sie AI
Fragen Sie AI
Fragen Sie alles oder probieren Sie eine der vorgeschlagenen Fragen, um unser Gespräch zu beginnen
Awesome!
Completion rate improved to 2.33
Prinzipien
Swipe um das Menü anzuzeigen
Die Prinzipien der Arbeit mit der Stream-API basieren auf den zentralen Konzepten der funktionalen Programmierung und der Lazy Evaluation. Im Folgenden werden die wichtigsten Prinzipien der Stream-API vorgestellt.
Lazy Evaluation
Eines der grundlegenden Prinzipien der Stream-API ist die Lazy Evaluation.
Das bedeutet, dass intermediäre Operationen wie filter() oder map() nicht sofort ausgeführt werden. Sie bilden lediglich eine Kette von Aktionen, die erst dann ausgeführt wird, wenn eine abschließende Operation wie collect() oder forEach() aufgerufen wird.
Main.java
12345678910111213package com.example; import java.util.List; public class Main { public static void main(String[] args) { List<String> names = List.of("Alice", "Bob", "Charlie"); long count = names.stream() .filter(name -> name.startsWith("A")) // Forming the operation .count(); // Triggering execution System.out.println(count); // Output: 1 } }
Dieser Code erstellt einen Stream aus einer Liste von Strings, filtert die Elemente, sodass nur diejenigen erhalten bleiben, die mit dem Buchstaben A beginnen, und zählt, wie viele die Bedingung erfüllen. Das Ergebnis (1) wird ausgegeben, da nur Alice die Bedingung erfüllt.
Funktionaler Programmierstil
Die Stream API verwendet Lambda-Ausdrücke und funktionale Schnittstellen zur Datenverarbeitung. Anstelle des imperativen Ansatzes mit Schleifen wird beschrieben, was mit den Daten geschehen soll:
Main.java
1234567891011121314package com.example; import java.util.List; public class Main { public static void main(String[] args) { List<String> fruits = List.of("apple", "banana", "cherry", "apricot", "blueberry"); List<String> result = fruits.stream() .map(String::toUpperCase) // Convert all strings to uppercase .skip(3) .toList(); // Collect the result into a new list System.out.println(result); } }
Dieser Code erstellt einen Stream aus einer Liste von Früchten, wandelt die Strings mit map() in Großbuchstaben um und überspringt mit skip() die ersten drei Elemente. Das Ergebnis wird in eine neue Liste gesammelt und ausgegeben, beginnend ab dem vierten Element.
Unveränderlichkeit der Daten
Die Stream API verändert die Originaldaten nicht. Alle Operationen erzeugen einen neuen Stream oder liefern ein Ergebnis zurück, ohne die Sammlung oder das Array zu verändern. Dies erhöht die Datensicherheit und verhindert unerwartete Nebeneffekte.
Main.java
12345678910111213package com.example; import java.util.List; public class Main { public static void main(String[] args) { List<String> names = List.of("Alice", "Bob", "Charlie"); List<String> updateNames = names.stream() .filter(name -> name.startsWith("A")) .toList(); System.out.println(names); // Output: [Alice, Bob, Charlie] } }
Die Stream-API filtert die Listennamen, um einen neuen Stream updateNames zu erstellen, der nur Elemente enthält, die mit dem Buchstaben A beginnen. Die ursprüngliche Liste names bleibt jedoch unverändert, da die Stream-API die Daten nicht direkt verändert. Dies gewährleistet Datensicherheit und verhindert Nebenwirkungen.
Streams sind nur einmal konsumierbar
Ein Stream kann nur einmal verwendet werden. Nach Ausführung einer terminalen Operation steht der Stream für weitere Verarbeitung nicht mehr zur Verfügung.
Main.java
123456789101112package com.example; import java.util.List; import java.util.stream.Stream; public class Main { public static void main(String[] args) { Stream<String> stream = List.of("Alice", "Bob").stream(); stream.forEach(System.out::println); stream.forEach(System.out::println); // Error: Stream has already been used } }
Hier wird ein Stream aus einer Liste von Strings erstellt und jedes Element auf die Konsole ausgegeben. Nachdem der Stream einmal verwendet wurde, kann er nicht wiederverwendet werden, was zu einem Fehler führt, wenn versucht wird, forEach() erneut aufzurufen.
Parallele Verarbeitung
Die Stream-API unterstützt parallele Streams und ermöglicht dadurch eine schnellere Datenverarbeitung auf Mehrkernsystemen. Dies wird ausführlicher hier behandelt.
Main.java
1234567891011package com.example; import java.util.List; public class Main { public static void main(String[] args) { List<Integer> numbers = List.of(1, 2, 3, 4, 5); numbers.parallelStream() .forEach(System.out::println); // Elements are processed in parallel } }
Dieser Code erstellt einen parallelen Stream aus einer Liste von Zahlen und gibt jedes Element auf der Konsole aus. Die Verwendung von parallelStream() ermöglicht eine parallele Verarbeitung der Listenelemente, was die Ausführung beschleunigen kann, insbesondere bei großen Datenmengen.
Code-Sauberkeit und Lesbarkeit
Die Verwendung der Stream API macht den Code deklarativer. Anstatt zu beschreiben, wie eine Aufgabe ausgeführt werden soll (wie bei der Verwendung von Schleifen), wird beschrieben, was genau erledigt werden muss. Dies verbessert die Lesbarkeit und vereinfacht die Wartung des Codes.
Beispiel mit einer Schleife:
List<String> names = List.of("Alice", "Bob", "Charlie");
for (String name : names) {
System.out.println(name);
}
Beispiel mit der Stream-API:
List<String> names = List.of("Alice", "Bob", "Charlie");
names.stream().forEach(System.out::println);
Im ersten Schleifenbeispiel wird explizit beschrieben, wie durch die Liste iteriert und die Elemente ausgegeben werden, während im zweiten Beispiel mit der Stream-API lediglich angegeben wird, was gemacht werden soll: Durchlaufen der Elemente und deren Ausgabe. Dadurch wird der Code deklarativer und lesbarer.
Danke für Ihr Feedback!