Java 8 Stream

Java 8 新特性Neue Funktionen in Java 8


Die Java 8 API hat eine neue Abstraktion namens Stream hinzugefügt, mit der Sie Daten deklarativ verarbeiten können.

Stream bietet eine High-Level-Abstraktion für Java-Collection-Operationen und -Ausdrücke auf intuitive Weise, ähnlich wie beim Abfragen von Daten aus einer Datenbank mit SQL-Anweisungen.

Die Stream-API kann die Produktivität von Java-Programmierern erheblich verbessern und es ihnen ermöglichen, effizienten, sauberen und prägnanten Code zu schreiben.

Dieser Stil behandelt die Sammlung der zu verarbeitenden Elemente als Stream. Der Stream wird in einer Pipeline übertragen und kann an Pipeline-Knoten verarbeitet werden, wie z. B. Filtern, Sortieren, Aggregieren usw.

Der Element-Stream durchläuft Zwischenoperationen in der Pipeline, und schließlich werden durch eine terminale Operation die vorherigen Verarbeitungsergebnisse erhalten.

+--------------------+       +------+   +------+   +---+   +-------+
| stream of elements +-----> |filter+-> |sorted+-> |map+-> |collect|
+--------------------+       +------+   +------+   +---+   +-------+

Der obige Prozess wird in Java-Code umgewandelt als:

List<Integer> transactionsIds = 
widgets.stream()
             .filter(b -> b.getColor() == RED)
             .sorted((x,y) -> x.getWeight() - y.getWeight())
             .mapToInt(Widget::getWeight)
             .sum();

Was ist Stream?

Stream ist eine Warteschlange von Elementen aus einer Datenquelle und unterstützt Aggregatoperationen.

  • Elemente sind Objekte eines bestimmten Typs und bilden eine Warteschlange. Stream in Java speichert keine Elemente; stattdessen berechnet er sie bei Bedarf.
  • DatenquelleDie Quelle des Streams. Sie kann eine Collection, ein Array, ein I/O-Kanal, ein Generator usw. sein.
  • AggregatoperationenOperationen ähnlich wie SQL-Anweisungen, wie filter, map, reduce, find, match, sorted usw.

Anders als bei früheren Collection-Operationen haben Stream-Operationen zwei grundlegende Merkmale:

  • PipeliningPipelining: Zwischenoperationen geben alle das Stream-Objekt selbst zurück. Dadurch können mehrere Operationen zu einer Pipeline verkettet werden, ganz wie bei einem Fluent-Stil. Dies ermöglicht die Optimierung von Operationen, wie Lazy Evaluation und Kurzschlussauswertung.
  • Interne IterationInterne Iteration: Früher erfolgte der Durchlauf einer Collection über Iterator oder For-Each, wobei explizit außerhalb der Collection iteriert wurde, was als externe Iteration bezeichnet wird. Stream bietet eine interne Iterationsmethode, die über das Visitor-Muster implementiert wird.

Streams generieren

In Java 8 hat die Collection-Schnittstelle zwei Methoden zum Erzeugen von Streams:

  • stream()− Erstellt einen seriellen Stream für die Collection.

  • parallelStream()− Erstellt einen parallelen Stream für die Collection.

List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl"); List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());

forEach

Stream stellt eine neue Methode 'forEach' bereit, um jedes Datum im Stream zu durchlaufen. Der folgende Codeausschnitt verwendet forEach, um 10 Zufallszahlen auszugeben:

Random random = new Random(); random.ints().limit(10).forEach(System.out::println);

map

Die map-Methode wird verwendet, um jedes Element auf sein entsprechendes Ergebnis abzubilden. Der folgende Codeausschnitt verwendet map, um die Quadrate der Elemente auszugeben:

List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5); //Die entsprechenden Quadratzahlen abrufen List<Integer> squaresList = numbers.stream().map( i -> i*i).distinct().collect(Collectors.toList());

filter

Die filter-Methode wird verwendet, um Elemente basierend auf einer festgelegten Bedingung herauszufiltern. Der folgende Codeausschnitt verwendet die filter-Methode, um leere Zeichenketten herauszufiltern:

List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl"); //Die Anzahl der leeren Zeichenketten abrufen long count = strings.stream().filter(string -> string.isEmpty()).count();

limit

Die limit-Methode wird verwendet, um einen Stream mit einer angegebenen Anzahl zu erhalten. Der folgende Codeausschnitt verwendet die limit-Methode, um 10 Datenelemente auszugeben:

Random random = new Random(); random.ints().limit(10).forEach(System.out::println);

sorted

Die sorted-Methode wird verwendet, um den Stream zu sortieren. Der folgende Codeausschnitt verwendet die sorted-Methode, um die 10 ausgegebenen Zufallszahlen zu sortieren:

Random random = new Random(); random.ints().limit(10).sorted().forEach(System.out::println);

Paralleles Programm

parallelStream ist eine alternative Methode für die parallele Stream-Verarbeitung. Im folgenden Beispiel verwenden wir parallelStream, um die Anzahl leerer Zeichenfolgen auszugeben:

List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl"); //Die Anzahl der leeren Zeichenketten abrufen long count = strings.parallelStream().filter(string -> string.isEmpty()).count();

Wir können einfach zwischen sequenzieller und paralleler Ausführung wechseln.


Collectors

Die Klasse Collectors implementiert viele Reduktionsoperationen, wie das Umwandeln von Streams in Sammlungen und das Aggregieren von Elementen. Collectors können verwendet werden, um Listen oder Zeichenfolgen zurückzugeben:

List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl"); List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList()); System.out.println("Gefilterte Liste:" + filtered); String mergedString = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.joining(", ")); System.out.println("Zusammengeführte Zeichenfolgen:" + mergedString);

Statistiken

Darüber hinaus sind einige Collector, die statistische Ergebnisse liefern, ebenfalls sehr nützlich. Sie werden hauptsächlich für primitive Typen wie int, double und long verwendet und können verwendet werden, um statistische Ergebnisse wie die folgenden zu erzeugen.

List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5); IntSummaryStatistics stats = numbers.stream().mapToInt((x) -> x).summaryStatistics(); System.out.println("Die größte Zahl in der Liste:" + stats.getMax()); System.out.println("Die kleinste Zahl in der Liste:" + stats.getMin()); System.out.println("Summe aller Zahlen:" + stats.getSum()); System.out.println("Durchschnitt:" + stats.getAverage());

Vollständiges Stream-Beispiel

Fügen Sie den folgenden Code in die Datei Java8Tester.java ein:

Java8Tester.java-Datei

import java.util.ArrayList; import java.util.Arrays; import java.util.IntSummaryStatistics; import java.util.List; import java.util.Random; import java.util.stream.Collectors; import java.util.Map; public class Java8Tester { public static void main(String args[]){ System.out.println("Mit Java 7:"); //Leere Strings zählen List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl"); System.out.println("Liste:" +strings); long count = getCountEmptyStringUsingJava7(strings); System.out.println("Anzahl leerer Strings:" + count); count = getCountLength3UsingJava7(strings); System.out.println("Anzahl der Strings mit Länge 3:" + count); //Leere Strings entfernen List<String> filtered = deleteEmptyStringsUsingJava7(strings); System.out.println("Gefilterte Liste:" + filtered); //Leere Zeichenfolgen entfernen und sie mit Kommas zusammenführen String mergedString = getMergedStringUsingJava7(strings,", "); System.out.println("Zusammengeführte Zeichenfolgen:" + mergedString); List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5); //Ermittle die Quadrate der Listenelemente List<Integer> squaresList = getSquares(numbers); System.out.println("Liste der Quadratzahlen:" + squaresList); List<Integer> integers = Arrays.asList(1,2,13,4,15,6,17,8,19); System.out.println("Liste:" +integers); System.out.println("Die größte Zahl in der Liste:" + getMax(integers)); System.out.println("Die kleinste Zahl in der Liste:" + getMin(integers)); System.out.println("Summe aller Zahlen:" + getSum(integers)); System.out.println("Durchschnitt:" + getAverage(integers)); System.out.println("Zufallszahlen:"); //10 Zufallszahlen ausgeben Random random = new Random(); for(int i=0; i < 10; i++){ System.out.println(random.nextInt()); } System.out.println("Mit Java 8:"); System.out.println("Liste:" +strings); count = strings.stream().filter(string->string.isEmpty()).count(); System.out.println("Anzahl leerer Strings:" + count); count = strings.stream().filter(string -> string.length() == 3).count(); System.out.println("Anzahl der Strings mit Länge 3:" + count); filtered = strings.stream().filter(string ->!string.isEmpty()).collect(Collectors.toList()); System.out.println("Gefilterte Liste:" + filtered); mergedString = strings.stream().filter(string ->!string.isEmpty()).collect(Collectors.joining(", ")); System.out.println("Zusammengeführte Zeichenfolgen:" + mergedString); squaresList = numbers.stream().map( i ->i*i).distinct().collect(Collectors.toList()); System.out.println("Liste der Quadrate: " + squaresList); System.out.println("Liste:" +integers); IntSummaryStatistics stats = integers.stream().mapToInt((x) ->x).summaryStatistics(); System.out.println("Die größte Zahl in der Liste:" + stats.getMax()); System.out.println("Die kleinste Zahl in der Liste:" + stats.getMin()); System.out.println("Summe aller Zahlen:" + stats.getSum()); System.out.println("Durchschnitt:" + stats.getAverage()); System.out.println("Zufallszahlen:"); random.ints().limit(10).sorted().forEach(System.out::println); //Parallele Verarbeitung count = strings.parallelStream().filter(string -> string.isEmpty()).count(); System.out.println("Anzahl leerer Strings:" + count); } private static int getCountEmptyStringUsingJava7(List<String> strings){ int count = 0; for(String string: strings){ if(string.isEmpty()){ count++; } } return count; } private static int getCountLength3UsingJava7(List<String> strings){ int count = 0; for(String string: strings){ if(string.length() == 3){ count++; } } return count; } private static List<String> deleteEmptyStringsUsingJava7(List<String> strings){ List<String> filteredList = new ArrayList<String>(); for(String string: strings){ if(!string.isEmpty()){ filteredList.add(string); } } return filteredList; } private static String getMergedStringUsingJava7(List<String> strings, String separator){ StringBuilder stringBuilder = new StringBuilder(); for(String string: strings){ if(!string.isEmpty()){ stringBuilder.append(string); stringBuilder.append(separator); } } String mergedString = stringBuilder.toString(); return mergedString.substring(0, mergedString.length()-2); } private static List<Integer> getSquares(List<Integer> numbers){ List<Integer> squaresList = new ArrayList<Integer>(); for(Integer number: numbers){ Integer square = new Integer(number.intValue() * number.intValue()); if(!squaresList.contains(square)){ squaresList.add(square); } } return squaresList; } private static int getMax(List<Integer> numbers){ int max = numbers.get(0); for(int i=1;i < numbers.size();i++){ Integer number = numbers.get(i); if(number.intValue() > max){ max = number.intValue(); } } return max; } private static int getMin(List<Integer> numbers){ int min = numbers.get(0); for(int i=1;i < numbers.size();i++){ Integer number = numbers.get(i); if(number.intValue() < min){ min = number.intValue(); } } return min; } private static int getSum(List numbers){ int sum = (int)(numbers.get(0)); for(int i=1;i < numbers.size();i++){ sum += (int)numbers.get(i); } return sum; } private static int getAverage(List<Integer> numbers){ return getSum(numbers) / numbers.size(); } }

Die Ausführung des obigen Skripts erzeugt die folgende Ausgabe:

$ javac Java8Tester.java 
$ java Java8Tester
使用 Java 7: 
列表: [abc, , bc, efg, abcd, , jkl]
空字符数量为: 2
字符串长度为 3 的数量为: 3
筛选后的列表: [abc, bc, efg, abcd, jkl]
合并字符串: abc, bc, efg, abcd, jkl
平方数列表: [9, 4, 49, 25]
列表: [1, 2, 13, 4, 15, 6, 17, 8, 19]
列表中最大的数 : 19
列表中最小的数 : 1
所有数之和 : 85
平均数 : 9
随机数: 
-393170844
-963842252
447036679
-1043163142
-881079698
221586850
-1101570113
576190039
-1045184578
1647841045
使用 Java 8: 
列表: [abc, , bc, efg, abcd, , jkl]
空字符串数量为: 2
字符串长度为 3 的数量为: 3
筛选后的列表: [abc, bc, efg, abcd, jkl]
合并字符串: abc, bc, efg, abcd, jkl
Squares List: [9, 4, 49, 25]
列表: [1, 2, 13, 4, 15, 6, 17, 8, 19]
列表中最大的数 : 19
列表中最小的数 : 1
所有数之和 : 85
平均数 : 9.444444444444445
随机数: 
-1743813696
-1301974944
-1299484995
-779981186
136544902
555792023
1243315896
1264920849
1472077135
1706423674
空字符串的数量为: 2

Java 8 新特性Neue Funktionen in Java 8

Weitere Erweiterungen