Java-Streams für Anfänger: Eine Einführung in die Verwendung von Streams in Java
Mit Java 8-Streams können Entwickler mithilfe einer Reihe vordefinierter Vorgänge präzise Daten aus einer großen Sammlung extrahieren.
Vor der Veröffentlichung von Java 8 wurde die Verwendung des Begriffs "Stream" in Java automatisch mit E / A verknüpft. In Java 8 wurde jedoch ein Stream eingeführt, der als eine Reihe von Rechenschritten bezeichnet werden kann, die in einer sogenannten "Stream-Pipeline" miteinander verkettet sind.
Dieser Artikel führt Sie in Java 8-Streams ein und zeigt, wie sie in Ihren Projekten nützlich sein können.
Was ist ein Stream?
Ein Stream ist eine Java-Schnittstelle, die eine Quelle verwendet, eine Reihe von Operationen zum Extrahieren bestimmter Daten ausführt und diese Daten dann der Anwendung zur Verwendung bereitstellt. Im Wesentlichen können Sie damit spezialisierte Daten aus einer Sammlung verallgemeinerter Daten extrahieren.
Wie Streams funktionieren
Eine Stream-Pipeline beginnt immer mit einer Quelle. Die Art der Quelle hängt von der Art der Daten ab, mit denen Sie sich befassen. Zwei der beliebtesten sind jedoch Arrays und Sammlungen.
Um die Sammlung in einen anfänglichen Stream umzuwandeln, müssen Sie die Funktion stream () zur Quelle hinzufügen. Dadurch wird die Quelle in die Stream-Pipeline eingefügt, wo verschiedene Zwischenoperationen (wie filter () und sort () ) darauf ausgeführt werden können.
Nachdem alle erforderlichen Zwischenoperationen ausgeführt wurden, können Sie eine Terminaloperation (z. B. forEach () ) einführen, die die zuvor aus der Quelle extrahierten Daten erzeugt.
Leben ohne Ströme
Java 8 wurde 2014 veröffentlicht, aber zuvor mussten Java-Entwickler noch spezielle Daten aus einer Sammlung allgemeiner Daten extrahieren.
Angenommen, Sie haben eine Liste von Zufallszeichen, die mit Zufallszahlen kombiniert werden, um eindeutige Zeichenfolgenwerte zu bilden. Sie möchten jedoch nur die Werte, die mit dem Zeichen „C“ beginnen, und das Ergebnis in aufsteigender Reihenfolge anordnen. So würden Sie diese Daten ohne Streams extrahieren.
Beispiel für das Filtern und Sortieren von Werten ohne Streams
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Main {
public static void main(String[] args) {
//declare and initialize the array list
List<String> randomValues = Arrays.asList(
"E11", "D12", "A13", "F14", "C15", "A16",
"B11", "B12", "C13", "B14", "B15", "B16",
"F12", "E13", "C11", "C14", "A15", "C16",
"F11", "C12", "D13", "E14", "D15", "D16"
);
//declare the array list will store needed values
List<String> requiredValues = new ArrayList<>();
//extracting the required values and storing them in reqquiredValues
randomValues.forEach(value -> {
if(value.startsWith("C")) {
requiredValues.add(value);
}
});
//sort the requiredValues in ascending order
requiredValues.sort((String value1, String value2) -> value1.compareTo(value2));
//print each value to the console
requiredValues.forEach((String value) -> System.out.println(value));
}
}
Sie müssen auch die Array-Liste deklarieren und initialisieren, unabhängig davon, ob Sie Streams oder eine andere Extraktionsmethode verwenden. Wenn Sie Streams verwenden würden, müssten Sie keine neue Variable deklarieren, die die erforderlichen Werte enthält, und im obigen Beispiel die anderen fünf Plus-Codezeilen nicht erstellen.
Der obige Code erzeugt die folgende Ausgabe in der Konsole:
C11
C12
C13
C14
C15
C16
Leben mit Strömen
Bei der Programmierung bedeutet Effizienz, dass mit deutlich weniger Code dasselbe Ergebnis erzielt wird. Genau das macht eine Stream-Pipeline für einen Programmierer. Wenn jemand das nächste Mal fragt: "Warum ist es wichtig, Streams in Ihrem Projekt zu verwenden?" Einfach ausgedrückt: "Streams unterstützen eine effiziente Programmierung."
Wenn Sie mit unserem obigen Beispiel fortfahren, transformiert die Einführung von Streams das gesamte Programm.
Filtern und Sortieren von Werten anhand eines Stream-Beispiels
import java.util.Arrays;
import java.util.List;
public class Main {
public static void main(String[] args) {
//declare and initialize the array list
List<String> randomValues = Arrays.asList(
"E11", "D12", "A13", "F14", "C15", "A16",
"B11", "B12", "C13", "B14", "B15", "B16",
"F12", "E13", "C11", "C14", "A15", "C16",
"F11", "C12", "D13", "E14", "D15", "D16"
);
//retrieves only values that start with C, sort them, and print them to the console.
randomValues.stream().filter(value->value.startsWith("C")).sorted().forEach(System.out::println);
}
}
Der obige Code zeigt, wie leistungsfähig die Stream-Schnittstelle ist. Es nimmt eine Liste von zufälligen Array-Werten und wandelt sie mit der Funktion stream () in einen Stream um. Der Stream wird dann mithilfe der Funktion filter () auf eine Array-Liste reduziert, die die erforderlichen Werte enthält (dh alle Werte, die mit C beginnen ) .
Wie Sie im obigen Beispiel sehen können, sind die C- Werte in der Array-Liste zufällig angeordnet. Wenn Sie den Stream an dieser Stelle in der Pipeline drucken würden, würde zuerst der Wert C15 gedruckt. Daher wird die Funktion sort () in die Stream-Pipeline eingeführt, um das neue Array in aufsteigender Reihenfolge neu anzuordnen.
Die letzte Funktion in der Stream-Pipeline ist eine forEach () -Funktion. Dies ist eine Terminalfunktion, die zum Stoppen der Stream-Pipeline verwendet wird und in der Konsole die folgenden Ergebnisse liefert:
C11
C12
C13
C14
C15
C16
Zwischenoperationen streamen
Es gibt eine umfangreiche Liste von Zwischenoperationen, die in einer Stream-Pipeline verwendet werden können.
Eine Stream-Pipeline beginnt immer mit einer einzelnen Quelle und einer stream () -Funktion und endet immer mit einer einzelnen Terminaloperation (obwohl mehrere verschiedene zur Auswahl stehen). Zwischen diesen beiden Abschnitten befindet sich jedoch eine Liste von sechs Zwischenoperationen, die Sie können verwenden.
In unserem obigen Beispiel werden nur zwei dieser Zwischenoperationen verwendet – filter () und sort () . Die von Ihnen gewählte Zwischenoperation hängt von den Aufgaben ab, die Sie ausführen möchten.
Wenn einer der Werte, die in unserer Array-Liste oben mit „C“ beginnen, in Kleinbuchstaben geschrieben wäre und wir dieselben Zwischenoperationen für sie ausführen würden, würden wir das folgende Ergebnis erhalten.
Beispiel für Filter- und Sortiervorgänge für Kleinbuchstaben
import java.util.Arrays;
import java.util.List;
public class Main {
public static void main(String[] args) {
//declare and initialize the array list
List<String> randomValues = Arrays.asList(
"E11", "D12", "A13", "F14", "C15", "A16",
"B11", "B12", "c13", "B14", "B15", "B16",
"F12", "E13", "C11", "C14", "A15", "c16",
"F11", "C12", "D13", "E14", "D15", "D16"
);
//retrieves only values that start with C, sort them, and print them to the console.
randomValues.stream().filter(value->value.startsWith("C")).sorted().forEach(System.out::println);
}
}
Der obige Code erzeugt die folgenden Werte in der Konsole:
C11
C12
C14
C15
Das einzige Problem mit der obigen Ausgabe ist, dass sie nicht alle C- Werte in unserer Array-Liste genau wiedergibt. Eine gute Möglichkeit, diesen kleinen Fehler zu beheben, besteht darin, eine weitere Zwischenoperation in die Stream-Pipeline einzuführen. Diese Operation wird als map () -Funktion bezeichnet.
Verwenden des Kartenfunktionsbeispiels
import java.util.Arrays;
import java.util.List;
public class Main {
public static void main(String[] args) {
//declare and initialize the array list
List<String> randomValues = Arrays.asList(
"E11", "D12", "A13", "F14", "C15", "A16",
"B11", "B12", "c13", "B14", "B15", "B16",
"F12", "E13", "C11", "C14", "A15", "c16",
"F11", "C12", "D13", "E14", "D15", "D16"
);
//transforms all lower case characters to upper case,
//retrieves only values that start with C, sort them, and print them to the console.
randomValues.stream().map(String::toUpperCase).filter(value->value.startsWith("C")).sorted().forEach(System.out::println);
}
}
Die Funktion map () transformiert ein Objekt von einem Zustand in einen anderen. In unserem obigen Beispiel werden alle Kleinbuchstaben in der Array-Liste in Großbuchstaben umgewandelt.
Wenn Sie die Funktion map () direkt vor der Funktion filter () platzieren, werden alle Werte, die mit C beginnen, aus der Array-Liste abgerufen.
Der obige Code erzeugt das folgende Ergebnis in der Konsole und repräsentiert erfolgreich alle C- Werte in der Array-Liste.
C11
C12
C13
C14
C15
C16
Die anderen drei Zwischenoperationen, die Sie in Ihren Anwendungen verwenden können, umfassen:
- spähen()
- Grenze()
- überspringen()
Java 8-Streams erleichtern die Erstellung von effizientem Code
Mit Java 8-Streams können Sie mit einer Codezeile zusätzliche spezifische, relevante Daten aus einer großen Quelle extrahieren. Solange Sie die anfängliche stream () -Funktion und einen Terminaloperator einschließen, können Sie eine beliebige Kombination von Zwischenoperationen verwenden, die passende Ausgaben für Ihr Ziel liefern.
Wenn Sie sich über die Codezeile wundern, die in unserer filter () -Funktion enthalten ist; Es ist als "Lambda-Ausdruck" bekannt. Lambda-Ausdrücke sind eine weitere Funktion, die mit Java 8 eingeführt wurde, und es enthält viele Nuggets, die Sie möglicherweise nützlich finden.