Java 8 - Stream
Stream è un nuovo livello astratto introdotto in Java 8. Utilizzando stream, è possibile elaborare i dati in modo dichiarativo simile alle istruzioni SQL. Ad esempio, considera la seguente istruzione SQL.
SELECT max(salary), employee_id, employee_name FROM Employee
L'espressione SQL sopra riportata restituisce automaticamente i dettagli del massimo dipendente stipendiato, senza eseguire alcun calcolo da parte dello sviluppatore. Utilizzando il framework delle raccolte in Java, uno sviluppatore deve utilizzare i loop ed eseguire controlli ripetuti. Un'altra preoccupazione è l'efficienza; poiché i processori multi-core sono disponibili a proprio agio, uno sviluppatore Java deve scrivere un'elaborazione del codice parallela che può essere piuttosto soggetta a errori.
Per risolvere tali problemi, Java 8 ha introdotto il concetto di flusso che consente allo sviluppatore di elaborare i dati in modo dichiarativo e di sfruttare l'architettura multicore senza la necessità di scrivere alcun codice specifico per esso.
Cos'è Stream?
Stream rappresenta una sequenza di oggetti da un'origine, che supporta le operazioni di aggregazione. Di seguito sono riportate le caratteristiche di uno Stream:
Sequence of elements- Un flusso fornisce un insieme di elementi di tipo specifico in modo sequenziale. Un flusso ottiene / calcola elementi su richiesta. Non memorizza mai gli elementi.
Source - Stream accetta raccolte, array o risorse I / O come origine di input.
Aggregate operations - Stream supporta operazioni aggregate come filtro, mappa, limite, riduzione, trova, corrispondenza e così via.
Pipelining- La maggior parte delle operazioni di flusso restituisce il flusso stesso in modo che il risultato possa essere pipeline. Queste operazioni sono chiamate operazioni intermedie e la loro funzione è quella di prendere input, elaborarli e restituire l'output alla destinazione. Il metodo collect () è un'operazione terminale che è normalmente presente alla fine dell'operazione di pipelining per contrassegnare la fine del flusso.
Automatic iterations - Le operazioni di flusso eseguono le iterazioni internamente sugli elementi di origine forniti, a differenza delle raccolte in cui è richiesta un'iterazione esplicita.
Generazione di flussi
Con Java 8, l'interfaccia Collection ha due metodi per generare un flusso.
stream() - Restituisce un flusso sequenziale considerando la raccolta come fonte.
parallelStream() - Restituisce un flusso parallelo considerando la raccolta come origine.
List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());
per ciascuno
Stream ha fornito un nuovo metodo "forEach" per iterare ogni elemento dello stream. Il seguente segmento di codice mostra come stampare 10 numeri casuali usando forEach.
Random random = new Random();
random.ints().limit(10).forEach(System.out::println);
carta geografica
Il metodo "map" viene utilizzato per mappare ogni elemento al risultato corrispondente. Il seguente segmento di codice stampa quadrati di numeri univoci utilizzando map.
List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
//get list of unique squares
List<Integer> squaresList = numbers.stream().map( i -> i*i).distinct().collect(Collectors.toList());
filtro
Il metodo "filtro" viene utilizzato per eliminare gli elementi in base a un criterio. Il seguente segmento di codice stampa un conteggio delle stringhe vuote utilizzando il filtro.
List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
//get count of empty string
int count = strings.stream().filter(string -> string.isEmpty()).count();
limite
Il metodo "limit" viene utilizzato per ridurre le dimensioni del flusso. Il seguente segmento di codice mostra come stampare 10 numeri casuali utilizzando limit.
Random random = new Random();
random.ints().limit(10).forEach(System.out::println);
smistato
Il metodo "ordinato" viene utilizzato per ordinare il flusso. Il seguente segmento di codice mostra come stampare 10 numeri casuali in un ordine ordinato.
Random random = new Random();
random.ints().limit(10).sorted().forEach(System.out::println);
Elaborazione parallela
parallelStream è l'alternativa di stream per l'elaborazione parallela. Dai un'occhiata al seguente segmento di codice che stampa un conteggio di stringhe vuote usando parallelStream.
List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
//get count of empty string
long count = strings.parallelStream().filter(string -> string.isEmpty()).count();
È molto facile passare tra flussi sequenziali e paralleli.
Collezionisti
I servizi di raccolta vengono utilizzati per combinare il risultato dell'elaborazione sugli elementi di un flusso. I servizi di raccolta possono essere utilizzati per restituire un elenco o una stringa.
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("Filtered List: " + filtered);
String mergedString = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.joining(", "));
System.out.println("Merged String: " + mergedString);
Statistiche
Con Java 8, i raccoglitori di statistiche vengono introdotti per calcolare tutte le statistiche quando viene eseguita l'elaborazione del flusso.
List numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
IntSummaryStatistics stats = numbers.stream().mapToInt((x) -> x).summaryStatistics();
System.out.println("Highest number in List : " + stats.getMax());
System.out.println("Lowest number in List : " + stats.getMin());
System.out.println("Sum of all numbers : " + stats.getSum());
System.out.println("Average of all numbers : " + stats.getAverage());
Esempio di flusso
Crea il seguente programma Java utilizzando qualsiasi editor di tua scelta, ad esempio C: \> JAVA.
Java8Tester.java
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("Using Java 7: ");
// Count empty strings
List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
System.out.println("List: " +strings);
long count = getCountEmptyStringUsingJava7(strings);
System.out.println("Empty Strings: " + count);
count = getCountLength3UsingJava7(strings);
System.out.println("Strings of length 3: " + count);
//Eliminate empty string
List<String> filtered = deleteEmptyStringsUsingJava7(strings);
System.out.println("Filtered List: " + filtered);
//Eliminate empty string and join using comma.
String mergedString = getMergedStringUsingJava7(strings,", ");
System.out.println("Merged String: " + mergedString);
List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
//get list of square of distinct numbers
List<Integer> squaresList = getSquares(numbers);
System.out.println("Squares List: " + squaresList);
List<Integer> integers = Arrays.asList(1,2,13,4,15,6,17,8,19);
System.out.println("List: " +integers);
System.out.println("Highest number in List : " + getMax(integers));
System.out.println("Lowest number in List : " + getMin(integers));
System.out.println("Sum of all numbers : " + getSum(integers));
System.out.println("Average of all numbers : " + getAverage(integers));
System.out.println("Random Numbers: ");
//print ten random numbers
Random random = new Random();
for(int i = 0; i < 10; i++) {
System.out.println(random.nextInt());
}
System.out.println("Using Java 8: ");
System.out.println("List: " +strings);
count = strings.stream().filter(string->string.isEmpty()).count();
System.out.println("Empty Strings: " + count);
count = strings.stream().filter(string -> string.length() == 3).count();
System.out.println("Strings of length 3: " + count);
filtered = strings.stream().filter(string ->!string.isEmpty()).collect(Collectors.toList());
System.out.println("Filtered List: " + filtered);
mergedString = strings.stream().filter(string ->!string.isEmpty()).collect(Collectors.joining(", "));
System.out.println("Merged String: " + mergedString);
squaresList = numbers.stream().map( i ->i*i).distinct().collect(Collectors.toList());
System.out.println("Squares List: " + squaresList);
System.out.println("List: " +integers);
IntSummaryStatistics stats = integers.stream().mapToInt((x) ->x).summaryStatistics();
System.out.println("Highest number in List : " + stats.getMax());
System.out.println("Lowest number in List : " + stats.getMin());
System.out.println("Sum of all numbers : " + stats.getSum());
System.out.println("Average of all numbers : " + stats.getAverage());
System.out.println("Random Numbers: ");
random.ints().limit(10).sorted().forEach(System.out::println);
//parallel processing
count = strings.parallelStream().filter(string -> string.isEmpty()).count();
System.out.println("Empty 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();
}
}
Verifica il risultato
Compila la classe usando javac compilatore come segue -
C:\JAVA>javac Java8Tester.java
Ora esegui Java8Tester come segue:
C:\JAVA>java Java8Tester
Dovrebbe produrre il seguente risultato:
Using Java 7:
List: [abc, , bc, efg, abcd, , jkl]
Empty Strings: 2
Strings of length 3: 3
Filtered List: [abc, bc, efg, abcd, jkl]
Merged String: abc, bc, efg, abcd, jkl
Squares List: [9, 4, 49, 25]
List: [1, 2, 13, 4, 15, 6, 17, 8, 19]
Highest number in List : 19
Lowest number in List : 1
Sum of all numbers : 85
Average of all numbers : 9
Random Numbers:
-1279735475
903418352
-1133928044
-1571118911
628530462
18407523
-881538250
-718932165
270259229
421676854
Using Java 8:
List: [abc, , bc, efg, abcd, , jkl]
Empty Strings: 2
Strings of length 3: 3
Filtered List: [abc, bc, efg, abcd, jkl]
Merged String: abc, bc, efg, abcd, jkl
Squares List: [9, 4, 49, 25]
List: [1, 2, 13, 4, 15, 6, 17, 8, 19]
Highest number in List : 19
Lowest number in List : 1
Sum of all numbers : 85
Average of all numbers : 9.444444444444445
Random Numbers:
-1009474951
-551240647
-2484714
181614550
933444268
1227850416
1579250773
1627454872
1683033687
1798939493
Empty Strings: 2