[Java] Einführung in die Stream-API

Was ist die Stream API #?

Es ist wie eine Fortsetzung des Artikels hier.

Die Stream-API ist eine API zur Verarbeitung von Daten im PipeLine-Format. Extrahieren Sie einzelne Elemente aus einer Sammlung von Daten (Datenquelle) wie Sammlung, Array, Datei usw. Es bietet einen Mechanismus, um dies an den "Prozessablauf" (Stream) weiterzuleiten.

"Zwischenoperation", die das Ergebnis der Ausführung einer Funktionsoperation für Stream als Stream zurückgibt Es gibt eine "Beendigungsoperation", die das Verarbeitungsergebnis als Daten zurückgibt.

Da viele Methodenargumente eine funktionale Schnittstelle sowohl für Zwischen- als auch für Beendigungsoperationen benötigen. Wenn das Wissen im Lambda-Stil hier verwendet wird, ist es klug. Stream API.png

Stream ...? Unterscheidet es sich von I / O Stream?

Java stellt I / O-Stream im Paket java.io bereit. Die Bedeutung von Stream ist hier ein Konzept, das Eingabe und Ausgabe mit Stream vergleicht. Stream of Stream API ist ein Konzept, mit dem PipeLine Daten wie Stream verarbeitet.

Grundlagen der Stream-API

python


import java.util.ArrayList;
import java.util.Arrays;

public class Main {

    public static void main(String[] args) {

        //① Datenquelle vorbereiten
        var list = new ArrayList<String>(
        		Arrays.asList("tokyo", "nagoya", "osaka", "fukuoka", "hokkaido", "okinawa"));

        //② Erstellen Sie einen Stream
        list.stream().
            filter(s -> s.length() > 5).         //③ Zwischenverarbeitung durchführen
            map(String::toUpperCase).
            forEach(System.out::println);        //④ Führen Sie die Terminierungsverarbeitung durch

        //Ergebnis: NAGOYA FUKUOKA HOKKAIDO OKINAWA
    }
}

Die Stream-API-Verarbeitung besteht aus folgenden Elementen. ** ① Datenquelle vorbereiten → ② Stream-Generierung → ③ Zwischenverarbeitung wie Extraktion / Verarbeitung → ④ Terminierungsverarbeitung wie Ausgabe / Aggregation **

Im obigen Beispiel ist ① Erstellen Sie zunächst eine Datenquelle für ArrayList

(2) Erstellen Sie einen Stream. Da es hier auf ArrayList \ basiert Die Stream-Methode gibt auch ein Stream \ -Objekt zurück.

③ Verwenden Sie die Filtermethode, um "nur Werte mit mehr als 5 Zeichen zu extrahieren". "In Großbuchstaben konvertieren" mit Kartenmethode Es kann mehrere Zwischenprozesse geben. Sie können es weglassen.

(4) Geben Sie den erhaltenen Wert mit der Methode System.out :: println mit der Methode forEach aus. ** Die Kündigungsverarbeitung kann nicht weggelassen werden. ** ** **   Der Rückgabewert der Zwischenverarbeitung ist Stream \ . In der Stream-API wird der Operator "." Verwendet, um den Prozess von der Stream-Generierung bis zur Zwischenverarbeitung / Beendigungsverarbeitung auszuführen. Sie können sie alle miteinander verbinden und intelligent schreiben. (Wird als ** Methodenkette ** im Sinne der Methodenkette bezeichnet)

Eine Reihe von Stream-Verarbeitungen wird zum Zeitpunkt der Beendigungsverarbeitung ausgeführt. Auch wenn Vorgänge wie Extraktion / Verarbeitung in der Mitte aufgerufen werden, werden sie einmal gelagert und Es wird nicht vor Ort ausgeführt und wartet auf die Bearbeitung bis zur Beendigung der Bearbeitung. Dies wird als ** Verzögerungsverarbeitung ** bezeichnet.

Wie erstelle ich einen Stream?

Generiert aus Collection / Array

** Aus der Sammlung ** Collection.stream() ** Aus Array ** Arrays.stream(T[]) ** Von der Karte ** Map.entrySet().stream()

Es gibt auch eine parallelStream () -Methode als parallele Version der stream () -Methode. Die parallele Verarbeitung ist einfach durch Ersetzen des Streams durch parallelStream möglich. (stark…) Wenn die Anzahl der zu behandelnden Elemente groß ist, kann eine effiziente Verarbeitung durch Aktivieren der Parallelverarbeitung möglich sein. (Natürlich ist es aufgrund des Parallelisierungsaufwands nicht immer schnell.) Sie können auch vorhandene Streams parallelisieren oder serialisieren.

Stream-Generierung aus der Stream-Klasse

In der Stream-Klasse gibt es eine Factory-Methode zum Erstellen eines Streams. Die grundlegendste Methode ist die of-Methode, mit der das angegebene Argument für die Variablennummer in einen Stream konvertiert wird.

var stream = Stream.of("tokyo","osaka","nagoya");
stream.forEach(System.out::println); // tokyo, osaka, nagoya

Es gibt auch generate (), builder (), concat (), iterator (). Ich werde es hier weglassen.

Primitive Stream-Generierung

IntStream Stream spezialisiert auf int LongStream Stream spezialisiert mit langen DoubleStream Stream spezialisiert auf Double

IntStream.range (int start, int endExclusive) [Zweites Argument liegt außerhalb des Bereichs: offener Raum] IntStream.rangeClosed (int start, int endInclusive) [Zweites Argument liegt im Bereich: geschlossener Raum]

Ein Beispiel für die iterative Verarbeitung mit IntStream lautet wie folgt. Vergleichen Sie mit dem Fall der Verwendung der for-Anweisung. Es ist ein bisschen in Mode.

Wiederholen Sie dies mit for-Anweisung


for(int i = 1; i <= 5 ; i++){
   System.out.println(i);
}

Wiederholen Sie dies mit IntStream


IntStream.rangeClosed(1, 5).forEach(System.out::println);

Primitive Typen können daher nicht in Java-Generika-Typargumenten verwendet werden Das Schreiben wie Stream \ führt zu einem Fehler.

Zwischenverarbeitung

Es hat die Aufgabe, die im Stream fließenden Werte zu extrahieren / zu verarbeiten. Die Zwischenverarbeitung wird nur ausgeführt, wenn die Beendigungsverarbeitung aufgerufen wird. Es wird nicht jedes Mal ausgeführt, wenn es aufgerufen wird. filter Extrahiert den Wert unter den angegebenen Bedingungen.

Stream.of("tokyo", "nagoya", "osaka").filter(s -> s.startsWith("t")).forEach(System.out::println); //tokyo

map Verarbeiten Sie den angegebenen Wert.

Stream.of("tokyo", "nagoya", "osaka").map(s -> s.length)).forEach(System.out::println); //5, 6, 5

Beachten Sie, dass es unmittelbar nach der Erstellung Stream \ war, jetzt jedoch Stream \ nach der Map-Methode.

sorted Sortieren Sie die Elemente.

Stream.of("tokyo", "nagoya", "osaka").sorted().forEach(System.out::println); // nagoya, osaka, tokyo
Stream.of(2,1,3).sorted().forEach(System.out::println); // 1, 2, 3

Das Standardverhalten ist das Sortieren in natürlicher Reihenfolge. Wenn es sich um eine Zeichenfolge handelt, wird sie in Wörterbuchreihenfolge sortiert, und wenn es sich um einen numerischen Wert handelt, wird sie nach Größe sortiert. Wenn Sie Ihre eigene Sortierregel angeben möchten, legen Sie die Sortierregel mit einem Lambda-Ausdruck fest. Das Argument von sorted () ist die Composer-Schnittstelle.

Stream.of("tokyo", "nagoya", "osaka").
  sorted((str1, str2) -> str1.length() - str2.length()).forEach(System.out::println); // tokyo, osaka, nagoya

skip/limit überspringen: Elemente bis zu m überspringen limit: n + 1 und nachfolgende Elemente abschneiden

IntStream.range(1, 10).skip(3).limit(5).forEach(System.out::println); // 4, 5, 6, 7, 8

Überspringen Sie die ersten 4 Elemente mit der Sprungmethode Die Limit-Methode extrahiert 5 Elemente daraus. Beachten Sie das Argument, da die Limit-Methode für einen Stream funktioniert, der bereits abgeschnitten wurde.

peek Überprüfen Sie den Zwischenstatus von Stream. Die Peek-Methode selbst wirkt sich nicht auf Stream aus und wird daher hauptsächlich zum Debuggen verwendet.

Stream.of("tokyo", "nagoya", "osaka").peek(System.out::println).sorted().forEach(System.out::println);
//Ergebnis vor dem Sortieren: Tokio, nagoya,osaka ← Peek println
//Ergebnis nach dem Sortieren: Nagoya, osaka,tokyo ← für jeden Druck

distinct Entfernen Sie doppelte Werte.

Stream.of("tokyo", "nagoya", "osaka", "osaka", "nagoya", "tokyo").distinct().forEach(System.out::println);
// tokyo, nagoya, osaka

Beendigung

Es hat die Aufgabe, die im Stream fließenden Werte endgültig auszugeben / zu aggregieren. Denn Stream wird schließlich zusammen mit dem Aufruf der Terminierungsverarbeitung als Trigger verarbeitet. Im Gegensatz zur Zwischenverarbeitung kann die Beendigungsverarbeitung nicht weggelassen werden.

Weil der terminierte Stream nicht wiederverwendet werden kann Wenn Sie die Stream-Verarbeitung erneut ausführen möchten, müssen Sie den Stream selbst aus der Datenquelle neu generieren.

forEach Verarbeiten Sie einzelne Elemente der Reihe nach.

Stream.of("tokyo", "nagoya", "osaka").forEach(v -> System.out.println(v)); // tokyo, nagoya, osaka
Stream.of("tokyo", "nagoya", "osaka").forEach(System.out::println); // tokyo, nagoya, osaka

findFirst Holen Sie sich den ersten Wert.

System.out.println(Stream.of("tokyo", "nagoya", "osaka").filter(s -> s.startsWith("t")).findFirst().orElse("empty"));
// tokyo

Der Rückgabewert der findFirst-Methode ist vom Typ Optional, da es sich möglicherweise um einen leeren Stream handelt.

Wenn leer


System.out.println(Stream.of("tokyo", "nagoya", "osaka").filter(s -> s.startsWith("a")).findFirst().orElse("empty"));
// empty

anyMatch/allMatch/noneMatch Legt fest, ob der Wert eine bestimmte Bedingung erfüllt. In der Reihenfolge "ob es ein Element gibt, für das der bedingte Ausdruck wahr ist", "ob alle bedingten Ausdrücke wahr sind", "Sind nicht alle bedingten Ausdrücke wahr?"

System.out.println(Stream.of("tokyo", "nagoya", "osaka").anyMatch(v -> v.length() == 5)); // true
System.out.println(Stream.of("tokyo", "nagoya", "osaka").allMatch(v -> v.length() == 5)); // false
System.out.println(Stream.of("tokyo", "nagoya", "osaka").noneMatch(v -> v.length() == 5)); // false

toArray Konvertiert das Ergebnis der Stream-Verarbeitung als Zeichenfolgenarray.

var list = Stream.of("tokyo", "nagoya", "osaka").filter(s -> s.startsWith("t")).toArray();

sammeln (Sammlungsumwandlung)

Konvertiert das Ergebnis der Stream-Verarbeitung als Sammlung. Übergeben Sie die von der Collectors-Klasse bereitgestellte Konvertierungsmethode an die Collect-Methode. Verwenden Sie toList für die Konvertierung in List, toSet für die Konvertierung in Set und toMap für die Konvertierung in Map.

var list = Stream.of("tokyo", "nagoya", "osaka").filter(s -> s.startsWith("t")).collect(Collectors.toList());

Die Erfassungsmethode ist keine Methode für die Konvertierung von Sammlungen Es ist auch eine Methode, die eine Reduktionsverarbeitung durchführt. Der Fall der Reduktionsverarbeitung wird später beschrieben.

min/max Finden Sie den minimalen / maximalen Wert. Als Argument muss eine Vergleichsregel (Comparator) angegeben werden. Da der Rückgabewert vom Typ Optional ist, erfolgt er über orElse. (Es ist -1, was bedeutet, dass es nicht hier ist.)

System.out.println(Stream.of(1, 3, 2).min((int1, int2) -> int1 - int2).orElse(-1)); // 1
System.out.println(Stream.of(1, 3, 2).min((int1, int2) -> int2 - int1).orElse(-1)); // 3
System.out.println(Stream.of(8, 7, 9).max((int1, int2) -> int1 - int2).orElse(-1)); // 9
System.out.println(Stream.of(8, 7, 9).max((int1, int2) -> int2 - int1).orElse(-1)); // 7

count Finden Sie die Anzahl der Elemente.

System.out.println(Stream.of("tokyo", "nagoya", "osaka").filter(s -> s.length() > 5).count()); // 1

reduce Kombinieren Sie Stream-Werte zu einem (Reduktion). Die Reduzierungsmethode bietet drei Arten von Überlastung.

Mit einem Argument

Optional reduce(BinaryOperator accumulator); Da der Rückgabewert vom Typ Optional ist, erfolgt er über orElse.

Die Argumente sind das variable Ergebnis zum Speichern des Operationsergebnisses und die Variable str zum Empfangen einzelner Elemente.

Mit einem Argument


System.out.println(
    Stream.of("tokyo", "nagoya", "osaka").sorted()
        .reduce((result, str) -> { return result + "," + str;}).orElse("")); // nagoya,osaka,tokyo

Mit 2 Argumenten

T reduce(T identity, BinaryOperator accumulator); Sie können den Anfangswert mit dem ersten Argument erhalten. Das Ergebnis ist offensichtlich nicht null, daher ist es vom nicht optionalen Typ. Sie müssen OrElse nicht durchlaufen.

Mit 2 Argumenten


System.out.println(
    Stream.of("tokyo", "nagoya", "osaka").sorted()
        .reduce("hokkaido",  (result, str) -> { return result + "," + str;})); //hokkaido,nagoya,osaka,tokyo

Mit 3 Argumenten

U reduce(U identity, BiFunction<U, ? super T, U> accumulator, BinaryOperator combiner); Es kann ein wenig schwierig sein. Es wird verwendet, wenn der Elementtyp von Stream und der endgültige Elementtyp unterschiedlich sind. Ein Beispiel wird hier weggelassen. Wenn Sie weitere Details erfahren möchten, können Sie den Artikel [hier] lesen (https://qiita.com/megmogmog1965/items/c9cf8639fc40c63b0e0a).

sammeln (Reduktionsvorgang)

Sammeln Sie die Elemente in Stream in Collection usw. Während Reduzieren die Elemente in einem Stream auf einen einzelnen Wert wie int oder String reduziert, collect akkumuliert und gibt Werte für einen Variablencontainer wie Collection / StringBuilder (Variablenreduktion) zurück.

Das ist ein bisschen esoterisch, also werde ich es später aktualisieren ...

Am Ende

Ich plane, Java Gold SE 11 bis März zu bekommen. (Zunächst müssen Sie Java Silver SE 11 als Voraussetzung verwenden ...) In Gold ist die Fragenrate der Lambda-Expression / Stream-API sehr hoch, daher habe ich sie organisiert.

Java SE 11 ist eine Qualifikation, die erst vor etwa einem halben Jahr (Ende 2019/06) abgeschlossen wurde. Bisher war SE 8 die neueste Version. Ein Nachschlagewerk für Silver SE 11 wurde bereits veröffentlicht, Gold SE 11 wurde zu diesem Zeitpunkt (Dezember 2019) nicht als Referenz veröffentlicht. Im Gegensatz zum SE 8-Test verwendet der SE 11-Test die Lambda-Ausdrucks- / Stream-API. Ich denke, es wird auf SE 11 basieren, also seien Sie bitte vorsichtig, wenn Sie die Prüfung ablegen.

Recommended Posts