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.
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.
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
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"));
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]
Die Beendigungsoperation kann grob in vier Prozesse unterteilt werden.
--Suche --Anhäufung
Dieses Mal werde ich die Methoden in vier Teilen vorstellen.
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.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
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.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.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());
});
Grundlagen der Stream-API Ich habe versucht, den Text in die Java 8-Stream-API zu streamen (Beendigungsoperation)
Recommended Posts