[JAVA] Ich habe versucht, die Stream-API zusammenzufassen

Was ist die Stream-API?

Die Stream-API ist, wie der Name schon sagt, eine Gruppe von APIs zur Verarbeitung fließender Daten und Ereignisse, die als Stream bezeichnet werden. In Java SE 8 hinzugefügt Stream wird basierend auf einem Datensatz wie List oder Map generiert. Das Ergebnis wird durch Ausführen von 0 oder mehr Zwischenoperationen und 1 Beendigungsoperation erhalten.

Verwendung der Stream-API

Nachdem wir einen groben Überblick erhalten haben, schauen wir uns die Quelle an und vergleichen die Verarbeitung mit Stream mit der Verarbeitung ohne Stream. Als Beispiel werde ich den Code schreiben, der List verarbeitet, und ihn einzeln verarbeiten.

Kein Strom


		List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5);
		for (Integer i : integerList) {
		    if (i % 2 == 0) {
		        System.out.println(i);
		    }

Stream-Beschreibung


		List<Integer> integerList = Arrays.asList(1,2,3,4);
		integerList.stream()
		           .filter(i -> i % 2 ==0)
		           .forEach(i -> System.out.println(i));

Ausgabeergebnis


2
4

Es ist ein Code, der eine einfache Liste mit einer for-Anweisung umdreht, mit einer if-Anweisung ein Urteil abgibt und diese ausgibt. Der Teil, der durch Drehen mit der for-Anweisung verarbeitet werden soll, kann durch stream ersetzt werden, und die if-Anweisung schränkt die internen Elemente mit filter direkt ein und gibt die verbleibenden Elemente mit forEach aus.

Ersteres ist für diejenigen, die vor Java8 an die Umgebung gewöhnt sind, möglicherweise leichter zu erkennen, letzteres ist jedoch einfacher zu verwenden und zu verstehen, wenn Sie sich an das Schreiben von Streams gewöhnt haben. Im Stream sind die Methoden in Einheiten unterteilt, mit denen Sie wissen, was zu tun ist. Wenn Sie die Verwendung der einzelnen Methoden unterdrücken, handelt es sich um eine Beschreibungsmethode, mit der Sie den Verarbeitungsinhalt intuitiv erfassen können.

Die Stream-API wird verwendet, indem kontinuierlich die Prozesse "Erstellen", "Bearbeiten" und "Kombinieren" eines Streams für eine Datenstruktur ausgeführt werden.

Operation generieren

Es gibt ungefähr die folgenden Methoden zum Erstellen eines Streams.

java.util.stream.Stream#of(T...) : Stream java.util.stream.Stream.Builder#build() : Stream java.util.Collection#stream() : Stream java.util.Arrays#stream(T[]) : Stream java.io.BufferedReader#lines() : Stream java.nio.Files#lines(Path) : Stream java.nio.Files#lines(Path, Charset) : Stream java.util.regex.Pattern#splitAsStream(CharSequence) : Stream java.lang.CharSequence#chars() : IntStream java.lang.CharSequence#charPoints() : IntStream

Dieses Mal werde ich zwei Fälle vorstellen, einen aus einer Sammlungsschnittstelle wie List und Set, die häufig verwendet werden, und den anderen aus einem Array. Verwenden Sie die stream () -Methode, um einen Stream aus einer Liste oder einem Set zu erstellen. Wenn Sie einen Stream aus einem Array erstellen möchten, verwenden Sie die Methode Arrays.stream ().

python


		//Listen-Stream-Verarbeitung
		List<Integer> numbers = List.of(3, 1, -4, 1, -5, 9, -2, 6, 5, 3, 5);
		Stream<Integer> stream = numbers.stream();
		//Steramverarbeitung von Arrays
		int[] array = {3, 1, -4, 1, -5, 9, -2, 6, 5, 3, 5};
		IntStream stream = Arrays.stream(array);

Wenn Sie einen Stream aus einer Map erstellen möchten, gibt es keine API, um einen Stream direkt aus der Map zu erstellen. Erstellen Sie daher einen Stream aus dem Set , das mit der entrySet-Methode der Map abgerufen wurde.

		Map<String, Integer> map = Map.of("key1", 3, "ke2", 1, "key3", -4, "key4", 1);
		Stream<Entry<String, Integer>> stream = map.entrySet().stream();

Mit der Files.line-Methode kann eine Textdatei zeilenweise gelesen und als Zeichenfolgenstrom verwendet werden.

		Stream<String> lines = Files.lines(Path.of("/tmp/test.txt"));

Zwischenbetrieb

Der in Stream ausgeführte Prozess wird als Zwischenoperation bezeichnet. Die Zwischenoperationen haben die folgenden Methoden.

peek(Consumer<? super T> action) skip(long maxSize) limit(long maxSize) filter(Predicate<? super T> predicate) distinct() sorted() / sorted(Comparator<? super T> comparator) map(Function<? super T,? extends R> mapper) flatMap(Function<? super T,? extends Stream<? extends R>> mapper) parallel() sequencial() unordered()

Diesmal die häufig verwendete Methode Ich werde mich auf Sortieren, Zuordnen und Filtern konzentrieren.

1.sorted() sortiert () gibt einen Stream mit sortierten Elementen des Streams zurück. Es gibt zwei Überladungen für sorted () mit und ohne Argumente.

Sorted () ohne Argumente sortiert die Elemente einfach in aufsteigender natürlicher Reihenfolge. (Die Elementklasse muss jedoch Comaprable sein.

Wenn Sie in "unnatürlicher" oder absteigender Reihenfolge sortieren möchten, übergeben Sie einen benutzerdefinierten Komparator als Funktion mit Argumenten an soreted (). (Wenn Sie es in Lambda angeben, ist es einfacher, Comparator # compare () zu verwenden.)

		List<String> array = Arrays.asList("a","1","-2","Ah","A","123");

		System.out.println("--Keine Argumente--");
		//Keine Argumente
		array.stream()
			.sorted()  //Natürliche Ordnung aufsteigende Ordnung
			.forEach(System.out::println);

		System.out.println("--Comparator--");
	    // Comparator
		array.stream()
	            .sorted(Comparator.reverseOrder()) //Natürliche Reihenfolge absteigende Reihenfolge
	            .forEach(System.out::println);

		System.out.println("--Lambda-Stil--");
	    //Lambda-Stil
		array.stream()
	            .sorted((l, r) -> l.length() - r.length()) //Länge der Zeichenfolge in absteigender Reihenfolge
	            .forEach(System.out::println);

		System.out.println("--Methodenreferenz--");
	    //Methodenreferenz(Comparable)
		array.stream()
	            .sorted(String::compareToIgnoreCase) //Fall ignorieren
	            .forEach(System.out::println);

		System.out.println("--Funktionsobjekt--");
	    //Funktionsobjekt
		array.stream()
	            .sorted(String.CASE_INSENSITIVE_ORDER) //Fall ignorieren
	            .forEach(System.out::println);

	    // java.util.List`Auch 1.Um 8`sort()`Wird mit der Standardmethode hinzugefügt.
	    //Dies ist wirtschaftlicher, wenn die Elementreihenfolge der Liste selbst geändert werden soll.
		System.out.println("--Nach Liste sortieren--");
	    //Komparator angeben
		array.sort(Comparator.reverseOrder());
	    array.stream()
	    	.forEach(System.out::println);

Ausgabeergebnis


--Keine Argumente--
-2
1
123
A
a
Ah
--Comparator--
Ah
a
A
123
1
-2
--Lambda-Stil--
a
1
Ah
A
-2
123
--Methodenreferenz--
-2
1
123
a
A
Ah
--Funktionsobjekt--
-2
1
123
a
A
Ah
--Nach Liste sortieren--
Ah
a
A
123
1
-2

2.filter()/distinct()

filter () und unique () verdünnen die Elemente von Stream anhand ihres Inhalts.

filter () ist eine Zwischenoperation, die die Elemente gemäß den Bedingungen eingrenzt und eine Prädikatfunktion (Prädikat) zur Beurteilung als Argument angibt. Solange das Prädikat nur den Wert des Elements betrachtet, ist filter () eine zustandslose Zwischenoperation. different () ist eine Zwischenoperation, bei der doppelte Elemente entfernt werden.

        System.out.println("--filter--");
		List array = Arrays.asList("a.txt","b.com","c.new");
        array.stream()
        .filter(s -> ((String) s).endsWith(".txt")) //Lambda-Stil
        .forEach(System.out::println);

        System.out.println("--distinct--");
        String data = "aaa aaa bbb aaa ccc bbb ccc ccc";
        String uniq = Stream.of(data.split("\\s"))
                .peek(s -> System.out.print("\n" +  s))
                .distinct()
                .peek(s -> System.out.print("\t" + s))
                .collect(Collectors.joining(","));
        System.out.println();
        System.out.println(uniq);

Ausführungsergebnis


--filter--
a.txt
--distinct--

aaa	aaa
aaa
bbb	bbb
aaa
ccc	ccc
bbb
ccc
ccc
aaa,bbb,ccc

3.map()

map () gibt einen Stream zurück, dessen Elemente von der angegebenen Funktion transformiert wurden. Der Rückgabetyp der Funktion kann den Typ des Stream-Elements ändern.

	    //Funktionsvorbereitung (Großschreibung des ersten Zeichens)
	    Function<String, String> capitalize = (String s) -> {
	        return String.format("%c%s",
	                Character.toTitleCase(s.charAt(0)),
	                s.substring(1));
	    };

	    List<String> words = Arrays.asList("aasDfag");
	    words = words.stream()
	    		.peek(System.out::println)
	            .map(s -> s.trim())        //Lambda-Stil
	            .filter(s -> !s.isEmpty())
	            .map(String::toLowerCase)  //Methodenreferenz
	            .peek(System.out::println)
	            .map(capitalize)           //Funktionsobjekt
	            .collect(Collectors.toList());
	    System.out.println(words);

Ausführungsergebnis


aasDfag
aasdfag
[Aasdfag]

Kündigungsoperation

Die Beendigungsoperation kann grob in vier Prozesse unterteilt werden.

--Suche --Anhäufung

Dieses Mal werde ich die Methoden in vier Teilen vorstellen.

1. Suchen

1.1. findFirst()/findAny()

findFirst () gibt das erste Element als Optional zurück. findAny () gibt das erste Element als Optional zurück. Optional kann leer sein.

	    String[] words = {"aaaaaa", "bbbbbb", "cccccc"};

	    List<String> list = Arrays.asList(words);
	    Optional<String> first = list.stream().findFirst();
	    first.ifPresent(s -> {
	        System.out.println(s);  // "aaaaaa"
	    });

	    Set<String> set = new HashSet<>(list);
	    Optional<String> any = set.stream().findAny();
	    any.ifPresent(s -> {
	        System.out.println(s);  // "cccccc"
	    });

1.2. allMatch() / anyMatch() / noneMatch()

allMatch () / anyMatch () / noneMatch () durchsucht das Stream-Ergebniselement basierend auf der angegebenen Prädikatfunktion (Prädikat) und ermittelt den Existenzstatus des übereinstimmenden Elements.

	    List<String> list = Arrays.asList("a","asdf","");
	    boolean ok;

	    //Lambda-Stil
	    ok = list.stream()
	            .allMatch(s -> s != null && !s.isEmpty()); //Enthält keine null und leeren Zeichenfolgen
	    System.out.println(ok);
	    //Methodenreferenz
	    ok = list.stream()
	            .allMatch(Objects::nonNull);    //Enthält keine Null
	    System.out.println(ok);
	    //Prädikatfunktion
	    ok = list.stream()
	            .noneMatch(Predicate.isEqual("")); //Kann null sein und enthält keine leeren Zeichenfolgen
	    System.out.println(ok);

Ausführungsergebnis


false
true
false

2. Aggregation

2.1. count() / min() / max()

count () zählt buchstäblich die Anzahl der Stream-Elemente. Da es wirklich zählt, dauert es einige Verarbeitungszeit.

    //Anzahl der Zeilen in der Textdatei
    int lc = (int) Files.lines(Paths.get("text.txt")).count();
    //Anzahl der Wörter im Text
    int wc = (int) Pattern.compile("\\W+").splitAsStream(text).count();
    //Zählen Sie den Unterschied in Buchstaben
    int vc = (int) text.codePoints().distinct().count();

Übergeben Sie eine Vergleichsfunktion (Komparator) an min () / max (), um die Maximal- und Minimalwerte der Elemente zu erhalten. Der Rückgabewert ist Optional , der leer ist, wenn keine Elemente vorhanden sind. Der Stream wird immer bis zum Ende geladen.

    List<String> list = ... ;
    Optional<String> min;

    // Comparator
    min = list.stream()
            .min(Comparator.naturalOrder()); //Die kleinste Zeichenfolge in lexikalischer Reihenfolge
    //Methodenreferenz
    min = list.stream()
            .min(String::compareToIgnoreCase); //Groß- und Kleinschreibung wird nicht berücksichtigt
    //Lambda-Stil
    min = list.stream()
            .min((l, r) -> l.length() - r.length()); //Kürzeste Saite
    // Comparable
    min = list.stream()
            .min(Comparator.comparing(s -> s.toUpperCase())); //Groß- und Kleinschreibung wird nicht berücksichtigt

Primitive Streams wie DoubleStream bieten Beendigungsoperationen wie sum () und durchschnittlich () sowie count () / min () / max ().

Es ist praktisch, den aggregierten Wert ohne Schleife abzurufen. Wenn Sie jedoch versuchen, anhand des aggregierten Werts zu berechnen, müssen Sie Stream viele Male ausführen, was ineffizient ist. Aus diesem Grund gibt es auch eine Beendigungsoperation namens summaryStatistics (), die jeden aggregierten Wert auf einmal annehmen kann.

2.2. reduce()

Verwenden Sie redu (), wenn Sie eine benutzerdefinierte Aggregatfunktion anwenden möchten. Beispielsweise kann es für die Verkettungsverarbeitung verwendet werden, die nicht einfach durch Join realisiert werden kann.

    //Extrahieren Sie das letzte Element
    Optional<String> last = stream.reduce((l, r) -> r);

    //Konvertieren Sie den Domainnamen in den Paketnamen
    String domain = "hoge.example.co.jp";
    //Kehren Sie die Elementreihenfolge um
    String pkg = Stream.of(domain.split("\\."))
            .reduce((l, r) -> r + "." + l).get();
    // jp.co.example.hoge

Um ehrlich zu sein, konnte ich nicht verstehen, wie man es benutzt. .. Ich werde es später nachschlagen und dem Artikel hinzufügen.

3. Konvertieren

3.1. toArray()

toArray () konvertiert Stream in ein Array seiner Elemente.


Stream<String> stream = Stream.of("a", "b", ...);

//Keine Argumente
Object[] arr = stream.toArray();

//Siehe Array-Konstruktor
String[] arr = stream.toArray(String[]::new);

//Lambda-Stil
String[] arr = stream.toArray((size) -> new String[size]);

3.2. collect() Vom Stream in Liste konvertieren. Rufen Sie für das Argument die Methode auf und definieren Sie sie, die als Sammlung mit der statischen Factory-Methode in `` `java.util.stream.Collectors``` gesammelt wird.

Java Collector Memo (Hishidamas Java8 Collector Memo)

//Sie können den Klassennamen weglassen, indem Sie Collectors statisch importieren.
//Platzhalter abhängig von den IDE-Einstellungen(*)Darf dich nicht benutzen lassen.
import static java.util.stream.Collectors.*;

    Stream<String> stream = ... ;

    //In String konvertieren(Verknüpfen)
    String text = stream.collect(joining());

    //In String konvertieren(Trennzeichenspezifikation)
    String csv = src.stream().collect(joining(", "));

    //In Liste konvertieren
    List<String> list = stream.collect(toList()); // ArrayList

    //In eine beliebige List-Klasse konvertieren
    List<String> list = stream
            .collect(toCollection(LinkedList::new)); // LinkedList

    //In Set konvertieren
    Set<String> set = stream.collect(toSet());  // HashSet

    //In eine beliebige Set-Klasse konvertieren
    SortedSet<String> set = stream
            .collect(toCollection(TreeSet::new)); //TreeSet sortiert

    LinkedHashSet<String> set = stream
            .collect(toCollection(LinkedHashSet::new)); //Pflegen Sie die LinkedHashSet-Elementreihenfolge

    //In Karte konvertieren
    // id -> object
    Map<Integer, User> map = users.stream()
            .collect(toMap(
                    e -> e.getId(),  //Ausnahme, wenn der Schlüssel doppelt vorhanden ist
                    e -> e           // value
            )); // HashMap

    // id -> name
    Map<Integer, User> map = users.stream()
            .collect(toMap(User::getId, User::getName));

    //In eine beliebige Map-Klasse konvertieren
    SortedMap<Integer, User> map = users.stream()
            .collect(toMap(
                    e -> e.getId(),
                    e -> e,
                    (l, r) -> r, //Überschreiben, wenn der Schlüssel doppelt vorhanden ist
                    TreeMap::new
            )); // TreeMap

4. Ausgabe

4.1. forEach() / forEachOrdered()

forEach () ist eine Beendigungsoperation, die die gesendeten Streamdaten ausgeben und konvertieren kann.


    List<String> list = Arrays.asList("a", "b", "c");

    //Stream für jeden()Ist eine Nebenwirkung
    //Ich möchte es mit Blöcken explizit machen
    list.stream()
            .forEach(s -> {
                System.out.println(s);
            });

    //Wenn Sie keine Blöcke verwenden, können Sie diese anzeigen und den Wert zurückgeben.
    list.stream().forEach(s -> System.out.println(s));

    // forEach()Es ist umständlich, Methodenreferenzen zu verwenden
    list.stream().forEach(System.out::println);

    //Iterable für jeden()
    list.forEach(s -> {
        System.out.println(s);
    });

    //Äquivalente Erweiterung für die Syntax
    for (String s : list) {
        System.out.println(s);
    }

    Map<String, String> map = new HashMap<>();

    //Eigentlich ist es auch in Map
    map.forEach((key, val) -> {
        System.out.format("%s=%s\n", key, val);
    });

    //Ich möchte Stream mit Karte verwenden
    map.entrySet().stream()
            .forEach(e -> {
                System.out.format("%s=%s\n", e.getKey(), e.getValue());
            });

Referenz

Grundlagen der Stream-API Ich habe versucht, den Text in die Java 8-Stream-API zu streamen (Beendigungsoperation)

Recommended Posts

Ich habe versucht, die Stream-API zusammenzufassen
[java8] Um die Stream-API zu verstehen
Ich habe versucht, die Methode zu erklären
Ich habe versucht, die Java8 Stream API zu verwenden
Ich habe versucht, das Java-Lernen zusammenzufassen (1)
Ich habe jetzt versucht, Java 8 zusammenzufassen
Ich habe die grundlegende Grammatik von Ruby kurz zusammengefasst
Ich habe versucht, Java-Lambda-Ausdrücke zusammenzufassen
Ich habe versucht, das Iterator-Muster zu implementieren
Was ist Docker? Ich habe versucht zusammenzufassen
Ich habe versucht zusammenzufassen, was bei der Site-Java-Ausgabe gefragt wurde.
[Rubiy] Heute Abend habe ich versucht, die Schleifenverarbeitung zusammenzufassen [Zeiten, Pause ...]
Sondervortrag über Multiskalensimulation: Ich habe versucht, den 5. zusammenzufassen
Sondervortrag über Multi-Scale-Simulation: Ich habe versucht, den 8. zusammenzufassen
Ich habe versucht, die Methoden von Java String und StringBuilder zusammenzufassen
Sondervortrag über Multi-Scale-Simulation: Ich habe versucht, den 7. zusammenzufassen
[Rails] Ich habe versucht, die Version von Rails von 5.0 auf 5.2 zu erhöhen
Ich habe versucht, die Sitzung in Rails zu organisieren
Ich habe versucht, Tomcat so einzustellen, dass das Servlet ausgeführt wird.
Ich habe versucht, die wichtigsten Punkte des gRPC-Designs und der Entwicklung zusammenzufassen
[Einführung in Java] Ich habe versucht, das Wissen zusammenzufassen, das ich für wesentlich halte
[Ruby] Ich habe versucht, die häufigen Methoden in Paiza zusammenzufassen
[Ruby] Ich habe versucht, die häufigen Methoden mit paiza ② zusammenzufassen
05. Ich habe versucht, die Quelle von Spring Boot zu löschen
Ich habe versucht, die Kapazität von Spring Boot zu reduzieren
Ich versuchte noch einmal zusammenzufassen, was auf den ersten Blick schwierig war
Ich habe versucht, Animationen mit der Blazor + Canvas-API zu zeichnen
[JavaScript] Der stärkste Fall, als ich versuchte, die Teile zusammenzufassen, die ich nicht verstehe
Ich habe das FizzBuzz-Problem ausprobiert
Ich habe versucht, node-jt400 (SQL-Stream)
[Java] Einführung in die Stream-API
Ich habe versucht, yum-cron zu verifizieren
Ich habe versucht, die Methode der gegenseitigen Teilung von Eugrid in Java zu implementieren
Ich habe versucht, den Betrieb der http-Anfrage (Put) mit dem Talented API Tester zu überprüfen
Ich habe versucht, die ähnliche Funktion durch asynchrone Kommunikation zu implementieren
[JDBC] Ich habe versucht, von Java aus auf die SQLite3-Datenbank zuzugreifen.
Ich möchte die Java 8 DateTime-API (jetzt) langsam verwenden.
Ich habe versucht, den Chat mit dem Minecraft-Server mit der Discord-API zu verknüpfen
Ich habe versucht, die Umgebung nach und nach mit Docker aufzubauen
Ich habe versucht, persönlich nützliche Apps und Entwicklungstools (Entwicklungstools) zusammenzufassen.
Was ich mit der Redmine REST API süchtig gemacht habe
Ich habe versucht, eine Umgebung mit WSL2 + Docker + VSCode zu erstellen
Ich habe versucht, persönlich nützliche Apps und Entwicklungstools (Apps) zusammenzufassen.
Jetzt ist es an der Zeit, mit der Stream-API zu beginnen
Ich war seltsamerweise süchtig danach, Javas Stream-API mit Scala zu verwenden
Ich habe versucht, eine Validierung durchzuführen, um zu vereinheitlichen, wie Hash-Tags geschrieben werden
Ich habe versucht, die Objektorientierung auf meine Weise zusammenzufassen.
Ich habe versucht, C # (Indexer) zu kauen.