Einführung in Java 8 Streams

1. Übersicht

In diesem Artikel werfen wir einen kurzen Blick auf eine der wichtigsten neuen Funktionen, die Java 8 hinzugefügt hat - Streams.

Wir erklären, worum es bei Streams geht, und zeigen anhand einfacher Beispiele die Erstellung und die grundlegenden Stream-Vorgänge.

2. API streamen

Eine der wichtigsten neuen Funktionen in Java 8 ist die Einführung der Stream-Funktionalität - java.util.stream -, die Klassen zum Verarbeiten von Elementsequenzen enthält.

Die zentrale API-Klasse ist der Stream. Der folgende Abschnitt zeigt, wie Streams mit den vorhandenen Datenproviderquellen erstellt werden können.

2.1. Stream-Erstellung

Streams können mit Hilfe der Methoden stream () und () aus verschiedenen Elementquellen erstellt werden, z. B. Sammlung oder Array :

String[] arr = new String[]{"a", "b", "c"}; Stream stream = Arrays.stream(arr); stream = Stream.of("a", "b", "c");

Eine Standardmethode von stream () wird zur Collection- Oberfläche hinzugefügt und ermöglicht das Erstellen eines Streams unter Verwendung einer beliebigen Collection als Elementquelle :

Stream stream = list.stream(); 

2.2. Multithreading mit Streams

Die Stream-API vereinfacht auch das Multithreading, indem die parallelStream () -Methode bereitgestellt wird, mit der Operationen über die Elemente des Streams im parallelen Modus ausgeführt werden.

Mit dem folgenden Code kann die Methode doWork () für jedes Element des Streams parallel ausgeführt werden:

list.parallelStream().forEach(element -> doWork(element));

Im folgenden Abschnitt werden einige der grundlegenden Stream-API-Vorgänge vorgestellt.

3. Stream-Operationen

Es gibt viele nützliche Vorgänge, die für einen Stream ausgeführt werden können.

Sie werden in geteilten Zwischenoperationen (return - Stream ) und Terminalbetrieb (Rück ein Ergebnis bestimmter Typ). Zwischenoperationen ermöglichen eine Verkettung.

Es ist auch erwähnenswert, dass Operationen an Streams die Quelle nicht ändern.

Hier ist ein kurzes Beispiel:

long count = list.stream().distinct().count();

Die Methode different () stellt also eine Zwischenoperation dar, die einen neuen Stream eindeutiger Elemente des vorherigen Streams erstellt. Die count () -Methode ist eine Terminaloperation , die die Größe des Streams zurückgibt.

3.1. Iterieren

Stream - API hilft Ersatz für , for-each und während Schleifen. Es ermöglicht die Konzentration auf die Logik der Operation, jedoch nicht auf die Iteration über die Folge von Elementen. Zum Beispiel:

for (String string : list) { if (string.contains("a")) { return true; } }

Dieser Code kann nur mit einer Zeile Java 8-Code geändert werden:

boolean isExist = list.stream().anyMatch(element -> element.contains("a"));

3.2. Filtern

Mit der filter () -Methode können wir einen Strom von Elementen auswählen, die ein Prädikat erfüllen.

Betrachten Sie beispielsweise die folgende Liste:

ArrayList list = new ArrayList(); list.add("One"); list.add("OneAndOnly"); list.add("Derek"); list.add("Change"); list.add("factory"); list.add("justBefore"); list.add("Italy"); list.add("Italy"); list.add("Thursday"); list.add(""); list.add("");

Der folgende Code erstellt einen Stream der Liste , findet alle Elemente dieses Streams, die char "d" enthalten , und erstellt einen neuen Stream, der nur die gefilterten Elemente enthält:

Stream stream = list.stream().filter(element -> element.contains("d"));

3.3. Kartierung

Um Elemente eines Streams durch Anwenden einer speziellen Funktion auf sie zu konvertieren und diese neuen Elemente in einem Stream zu sammeln , können Sie die map () -Methode verwenden:

List uris = new ArrayList(); uris.add("C:\\My.txt"); Stream stream = uris.stream().map(uri -> Paths.get(uri));

Der obige Code konvertiert Stream in den Stream, indem auf jedes Element des ursprünglichen Streams ein bestimmter Lambda-Ausdruck angewendet wird .

Wenn Sie einen Stream haben, in dem jedes Element eine eigene Folge von Elementen enthält und Sie einen Stream dieser inneren Elemente erstellen möchten, sollten Sie die flatMap () -Methode verwenden:

List details = new ArrayList(); details.add(new Detail()); Stream stream = details.stream().flatMap(detail -> detail.getParts().stream());

In diesem Beispiel haben wir eine Liste von Elementen vom Typ Detail . Die ausführliche Klasse enthält ein Feld PARTS , die a - Liste . Mit Hilfe der flatMap () -Methode wird jedes Element aus dem Feld PARTS extrahiert und dem neuen resultierenden Stream hinzugefügt. Danach geht der ursprüngliche Stream verloren .

3.4. Matching

Die Stream-API bietet eine praktische Reihe von Instrumenten, um Elemente einer Sequenz anhand eines Prädikats zu validieren. Dazu kann eine der folgenden Methoden verwendet werden: anyMatch (), allMatch (), noneMatch (). Ihre Namen sind selbsterklärend. Dies sind Terminaloperationen, die einen Booleschen Wert zurückgeben :

boolean isValid = list.stream().anyMatch(element -> element.contains("h")); // true boolean isValidOne = list.stream().allMatch(element -> element.contains("h")); // false boolean isValidTwo = list.stream().noneMatch(element -> element.contains("h")); // false

For empty streams, the allMatch() method with any given predicate will return true:

Stream.empty().allMatch(Objects::nonNull); // true

This is a sensible default, as we can't find any element that doesn't satisfy the predicate.

Similarly, the anyMatch() method always returns false for empty streams:

Stream.empty().anyMatch(Objects::nonNull); // false

Again, this is reasonable, as we can't find an element satisfying this condition.

3.5. Reduction

Stream API allows reducing a sequence of elements to some value according to a specified function with the help of the reduce() method of the type Stream. This method takes two parameters: first – start value, second – an accumulator function.

Imagine that you have a List and you want to have a sum of all these elements and some initial Integer (in this example 23). So, you can run the following code and result will be 26 (23 + 1 + 1 + 1).

List integers = Arrays.asList(1, 1, 1); Integer reduced = integers.stream().reduce(23, (a, b) -> a + b);

3.6. Collecting

The reduction can also be provided by the collect() method of type Stream. This operation is very handy in case of converting a stream to a Collection or a Map and representing a stream in the form of a single string. There is a utility class Collectors which provide a solution for almost all typical collecting operations. For some, not trivial tasks, a custom Collector can be created.

List resultList = list.stream().map(element -> element.toUpperCase()).collect(Collectors.toList());

Dieser Code verwendet die Operation collect () des Terminals , um einen Stream auf die Liste zu reduzieren .

4. Schlussfolgerung

In diesem Artikel haben wir kurz auf Java-Streams eingegangen - definitiv eine der interessantesten Java 8-Funktionen.

Es gibt viele fortgeschrittenere Beispiele für die Verwendung von Streams. Das Ziel dieses Aufsatzes war nur, eine schnelle und praktische Einführung in das zu geben, was Sie mit der Funktionalität anfangen können, und als Ausgangspunkt für das Erkunden und weitere Lernen.

Der dem Artikel beiliegende Quellcode ist auf GitHub verfügbar.